http.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. var AWS = require('./core');
  2. var inherit = AWS.util.inherit;
  3. /**
  4. * The endpoint that a service will talk to, for example,
  5. * `'https://ec2.ap-southeast-1.amazonaws.com'`. If
  6. * you need to override an endpoint for a service, you can
  7. * set the endpoint on a service by passing the endpoint
  8. * object with the `endpoint` option key:
  9. *
  10. * ```javascript
  11. * var ep = new AWS.Endpoint('awsproxy.example.com');
  12. * var s3 = new AWS.S3({endpoint: ep});
  13. * s3.service.endpoint.hostname == 'awsproxy.example.com'
  14. * ```
  15. *
  16. * Note that if you do not specify a protocol, the protocol will
  17. * be selected based on your current {AWS.config} configuration.
  18. *
  19. * @!attribute protocol
  20. * @return [String] the protocol (http or https) of the endpoint
  21. * URL
  22. * @!attribute hostname
  23. * @return [String] the host portion of the endpoint, e.g.,
  24. * example.com
  25. * @!attribute host
  26. * @return [String] the host portion of the endpoint including
  27. * the port, e.g., example.com:80
  28. * @!attribute port
  29. * @return [Integer] the port of the endpoint
  30. * @!attribute href
  31. * @return [String] the full URL of the endpoint
  32. */
  33. AWS.Endpoint = inherit({
  34. /**
  35. * @overload Endpoint(endpoint)
  36. * Constructs a new endpoint given an endpoint URL. If the
  37. * URL omits a protocol (http or https), the default protocol
  38. * set in the global {AWS.config} will be used.
  39. * @param endpoint [String] the URL to construct an endpoint from
  40. */
  41. constructor: function Endpoint(endpoint, config) {
  42. AWS.util.hideProperties(this, ['slashes', 'auth', 'hash', 'search', 'query']);
  43. if (typeof endpoint === 'undefined' || endpoint === null) {
  44. throw new Error('Invalid endpoint: ' + endpoint);
  45. } else if (typeof endpoint !== 'string') {
  46. return AWS.util.copy(endpoint);
  47. }
  48. if (!endpoint.match(/^http/)) {
  49. var useSSL = config && config.sslEnabled !== undefined ?
  50. config.sslEnabled : AWS.config.sslEnabled;
  51. endpoint = (useSSL ? 'https' : 'http') + '://' + endpoint;
  52. }
  53. AWS.util.update(this, AWS.util.urlParse(endpoint));
  54. // Ensure the port property is set as an integer
  55. if (this.port) {
  56. this.port = parseInt(this.port, 10);
  57. } else {
  58. this.port = this.protocol === 'https:' ? 443 : 80;
  59. }
  60. }
  61. });
  62. /**
  63. * The low level HTTP request object, encapsulating all HTTP header
  64. * and body data sent by a service request.
  65. *
  66. * @!attribute method
  67. * @return [String] the HTTP method of the request
  68. * @!attribute path
  69. * @return [String] the path portion of the URI, e.g.,
  70. * "/list/?start=5&num=10"
  71. * @!attribute headers
  72. * @return [map<String,String>]
  73. * a map of header keys and their respective values
  74. * @!attribute body
  75. * @return [String] the request body payload
  76. * @!attribute endpoint
  77. * @return [AWS.Endpoint] the endpoint for the request
  78. * @!attribute region
  79. * @api private
  80. * @return [String] the region, for signing purposes only.
  81. */
  82. AWS.HttpRequest = inherit({
  83. /**
  84. * @api private
  85. */
  86. constructor: function HttpRequest(endpoint, region) {
  87. endpoint = new AWS.Endpoint(endpoint);
  88. this.method = 'POST';
  89. this.path = endpoint.path || '/';
  90. this.headers = {};
  91. this.body = '';
  92. this.endpoint = endpoint;
  93. this.region = region;
  94. this._userAgent = '';
  95. this.setUserAgent();
  96. },
  97. /**
  98. * @api private
  99. */
  100. setUserAgent: function setUserAgent() {
  101. this._userAgent = this.headers[this.getUserAgentHeaderName()] = AWS.util.userAgent();
  102. },
  103. getUserAgentHeaderName: function getUserAgentHeaderName() {
  104. var prefix = AWS.util.isBrowser() ? 'X-Amz-' : '';
  105. return prefix + 'User-Agent';
  106. },
  107. /**
  108. * @api private
  109. */
  110. appendToUserAgent: function appendToUserAgent(agentPartial) {
  111. if (typeof agentPartial === 'string' && agentPartial) {
  112. this._userAgent += ' ' + agentPartial;
  113. }
  114. this.headers[this.getUserAgentHeaderName()] = this._userAgent;
  115. },
  116. /**
  117. * @api private
  118. */
  119. getUserAgent: function getUserAgent() {
  120. return this._userAgent;
  121. },
  122. /**
  123. * @return [String] the part of the {path} excluding the
  124. * query string
  125. */
  126. pathname: function pathname() {
  127. return this.path.split('?', 1)[0];
  128. },
  129. /**
  130. * @return [String] the query string portion of the {path}
  131. */
  132. search: function search() {
  133. var query = this.path.split('?', 2)[1];
  134. if (query) {
  135. query = AWS.util.queryStringParse(query);
  136. return AWS.util.queryParamsToString(query);
  137. }
  138. return '';
  139. },
  140. /**
  141. * @api private
  142. * update httpRequest endpoint with endpoint string
  143. */
  144. updateEndpoint: function updateEndpoint(endpointStr) {
  145. var newEndpoint = new AWS.Endpoint(endpointStr);
  146. this.endpoint = newEndpoint;
  147. this.path = newEndpoint.path || '/';
  148. if (this.headers['Host']) {
  149. this.headers['Host'] = newEndpoint.host;
  150. }
  151. }
  152. });
  153. /**
  154. * The low level HTTP response object, encapsulating all HTTP header
  155. * and body data returned from the request.
  156. *
  157. * @!attribute statusCode
  158. * @return [Integer] the HTTP status code of the response (e.g., 200, 404)
  159. * @!attribute headers
  160. * @return [map<String,String>]
  161. * a map of response header keys and their respective values
  162. * @!attribute body
  163. * @return [String] the response body payload
  164. * @!attribute [r] streaming
  165. * @return [Boolean] whether this response is being streamed at a low-level.
  166. * Defaults to `false` (buffered reads). Do not modify this manually, use
  167. * {createUnbufferedStream} to convert the stream to unbuffered mode
  168. * instead.
  169. */
  170. AWS.HttpResponse = inherit({
  171. /**
  172. * @api private
  173. */
  174. constructor: function HttpResponse() {
  175. this.statusCode = undefined;
  176. this.headers = {};
  177. this.body = undefined;
  178. this.streaming = false;
  179. this.stream = null;
  180. },
  181. /**
  182. * Disables buffering on the HTTP response and returns the stream for reading.
  183. * @return [Stream, XMLHttpRequest, null] the underlying stream object.
  184. * Use this object to directly read data off of the stream.
  185. * @note This object is only available after the {AWS.Request~httpHeaders}
  186. * event has fired. This method must be called prior to
  187. * {AWS.Request~httpData}.
  188. * @example Taking control of a stream
  189. * request.on('httpHeaders', function(statusCode, headers) {
  190. * if (statusCode < 300) {
  191. * if (headers.etag === 'xyz') {
  192. * // pipe the stream, disabling buffering
  193. * var stream = this.response.httpResponse.createUnbufferedStream();
  194. * stream.pipe(process.stdout);
  195. * } else { // abort this request and set a better error message
  196. * this.abort();
  197. * this.response.error = new Error('Invalid ETag');
  198. * }
  199. * }
  200. * }).send(console.log);
  201. */
  202. createUnbufferedStream: function createUnbufferedStream() {
  203. this.streaming = true;
  204. return this.stream;
  205. }
  206. });
  207. AWS.HttpClient = inherit({});
  208. /**
  209. * @api private
  210. */
  211. AWS.HttpClient.getInstance = function getInstance() {
  212. if (this.singleton === undefined) {
  213. this.singleton = new this();
  214. }
  215. return this.singleton;
  216. };