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