1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
|
8 krisbash 1.3 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
|
13 mike 1.1 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15 krisbash 1.3 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
|
18 mike 1.1 **
|
19 krisbash 1.3 ** See the Apache 2 License for the specific language governing permissions
|
20 mike 1.1 ** and limitations under the License.
21 **
22 **==============================================================================
23 */
24
25 #include <assert.h>
26 #include <ctype.h>
|
27 krisbash 1.3 #include "httpcommon.h"
|
28 mike 1.1 #include "httpclient.h"
29 #include <sock/addr.h>
30 #include <sock/sock.h>
31 #include <sock/selector.h>
|
32 krisbash 1.3 #include <pal/sleep.h>
|
33 mike 1.1 #include <base/buf.h>
34 #include <base/log.h>
35 #include <base/result.h>
|
36 krisbash 1.4 #include <pal/intsafe.h>
|
37 krisbash 1.3 #include <pal/strings.h>
38 #include <pal/format.h>
39 #include <pal/sleep.h>
|
40 mike 1.1 #include <base/paths.h>
41
|
42 krisbash 1.3 // #define ENABLE_TRACING 1
43 #ifdef ENABLE_TRACING
44 # define TRACING_LEVEL 4
45 # include <deprecated/logging/logging.h>
46 #else
47 # define LOGE2(a)
48 # define LOGW2(a)
49 # define LOGD2(a)
50 # define LOGX2(a)
51 #endif
52
|
53 mike 1.1 #ifdef CONFIG_POSIX
54 #include <openssl/ssl.h>
55 #include <openssl/err.h>
56 #else
57 /* ssl not supported in this configuration; just make compiler happy */
58 typedef void SSL;
59 typedef void SSL_CTX;
60 #define SSL_CTX_free(c)
61 #define SSL_new(c) 0
62 #define SSL_free(c)
63 #define SSL_set_connect_state(c)
64 #define SSL_set_fd(c,a) (a==a)
65 #define SSL_read(c,a,b) 0
66 #define SSL_write(c,a,b) 0
67 #define SSL_get_error(c,e) e
68 #define SSL_ERROR_WANT_WRITE 0
69 #define SSL_ERROR_WANT_READ 1
70 #define SSL_ERROR_SYSCALL 2
71
72 #ifdef EWOULDBLOCK
73 # undef EWOULDBLOCK
74 mike 1.1 #endif
75
76 #define EWOULDBLOCK 0
77
78 #ifdef EINPROGRESS
79 # undef EINPROGRESS
|
80 krisbash 1.3 #endif
|
81 mike 1.1
82 #define EINPROGRESS 0
83
84 #define ERR_get_error() 0
85 #define ERR_error_string_n(c,a,b) a[0]=0
86 #define SSL_accept(c) 0
87 #define SSL_connect(c) 0
88
89 #endif
90
91 /*
92 **==============================================================================
93 **
94 ** Local definitions:
95 **
96 **==============================================================================
97 */
98
99 static const MI_Uint32 _MAGIC = 0x5FC7B966;
100 static const MI_Uint32 MAX_HEADER_SIZE = 2 * 1024;
101 static const MI_Uint32 INITIAL_BUFFER_SIZE = 2 * 1024;
102 mike 1.1 static const MI_Uint32 DEFAULT_HTTP_TIMEOUT_USEC = 60 * 1000000;
103
104 typedef enum _Http_RecvState
105 {
106 RECV_STATE_HEADER,
107 RECV_STATE_CONTENT,
108 RECV_STATE_CHUNKHEADER,
109 RECV_STATE_CHUNKDATA
110 }
111 Http_RecvState;
112
|
113 krisbash 1.3 typedef struct _HttpClient_SR_SocketData
|
114 mike 1.1 {
115 /* based member*/
116 Handler base;
117
118 /* timeout */
119 MI_Uint64 timeoutUsec;
120
121 /* ssl part */
122 SSL* ssl;
123 MI_Boolean reverseOperations; /*reverse read/write Events/Handlers*/
124 MI_Boolean connectDone;
125
126 /* receiving data */
|
127 krisbash 1.3 __field_ecount(recvBufferSize) char* recvBuffer;
|
128 mike 1.1 size_t recvBufferSize;
|
129 krisbash 1.3 size_t receivedSize;
|
130 mike 1.1 Http_RecvState recvingState;
131 HttpClientHeaderField recvHeaderFields[64];
132 HttpClientResponseHeader recvHeaders;
133 MI_Sint64 contentLength;
|
134 krisbash 1.3 MI_Sint64 contentBegin;
135 MI_Sint64 contentEnd;
136 MI_Sint64 contentTotalLength;
|
137 mike 1.1 Page* recvPage;
138
|
139 krisbash 1.3 /* flag for a response from a HEAD request */
140 MI_Boolean headVerb;
141
|
142 mike 1.1 /* sending part */
143 Page* sendPage;
144 Page* sendHeader;
145 size_t sentSize;
146 Http_RecvState sendingState;
147
148 /* general operation status */
149 MI_Result status;
150
151 }
|
152 krisbash 1.3 HttpClient_SR_SocketData;
|
153 mike 1.1
154 struct _HttpClient
155 {
156 MI_Uint32 magic;
157 Selector internalSelector;
158 Selector* selector;
159 HttpClientCallbackOnStatus callbackOnStatus;
160 HttpClientCallbackOnResponse callbackOnResponse;
161 void* callbackData;
162 SSL_CTX* sslContext;
163
|
164 krisbash 1.3 HttpClient_SR_SocketData* connector;
|
165 mike 1.1
166 MI_Boolean internalSelectorUsed;
167 };
168
169
170 /* helper functions result */
171 typedef enum _Http_CallbackResult
172 {
|
173 krisbash 1.3 PRT_RETURN_FALSE,
|
174 mike 1.1 PRT_RETURN_TRUE,
|
175 krisbash 1.3 PRT_CONTINUE
|
176 mike 1.1 }
177 Http_CallbackResult;
178
179
180 MI_INLINE MI_Uint8 _ToLower(MI_Uint8 x)
181 {
182 return (MI_Uint8)tolower(x);
183 }
184
185 #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8) | (((MI_Uint16)len)) )
186
|
187 krisbash 1.3 _Return_type_success_(return == MI_TRUE)
|
188 mike 1.1 static MI_Boolean _getNameValuePair(
|
189 krisbash 1.3 _Inout_ CharPtr* line,
190 _Out_ CharPtr* value,
191 _Out_ int* nameHashCode)
|
192 mike 1.1 {
193 int len = 0;
194 char* p;
195 /* find name end /hash-code */
196
|
197 krisbash 1.3 if ((*line)[0] == '\0')
198 {
199 return MI_FALSE;
200 }
201
|
202 mike 1.1 *nameHashCode = _ToLower((MI_Uint8)(*line)[0])<<16;
203
|
204 krisbash 1.3 for (len = 1; (*line)[len] != '\0' && (*line)[len] != ':' && (*line)[len] != '\r'; len++)
|
205 mike 1.1 ;
206
207 if ((*line)[len] != ':')
208 return MI_FALSE;
209
210 *nameHashCode |= (len) | _ToLower((MI_Uint8)(*line)[len-1])<<8;
211 (*line)[len] = 0;
212 p = *line + len + 1;
213
214 /* skip spaces in value */
215 while (p[0] == ' ' || p[0] == '\t')
216 p++;
217
218 *value = p;
219
220 /* skip to end of line */
|
221 krisbash 1.3 for ( ; p[0]; )
|
222 mike 1.1 {
|
223 krisbash 1.3 if (p[0] != '\0' && p[1] != '\0' && p[2] != '\0' &&
224 p[0] == '\r' && p[1] == '\n' &&
225 p[2] != ' ' && p[2] != '\t')
|
226 mike 1.1 {
|
227 krisbash 1.3 p[0] = '\0';
|
228 mike 1.1 (*line) = p + 2;
229 break;
230 }
|
231 krisbash 1.3 p++;
|
232 mike 1.1 }
233
234 /* remove trailing spaces */
235 p--;
|
236 krisbash 1.3 #ifdef _PREFAST_
237 #pragma prefast (push)
238 #pragma prefast (disable: 26001)
239 #endif
240 /* disabling IPv6 OACR warnings - D3M bug 56 */
|
241 mike 1.1 while (p[0] == ' ' || p[0] == '\t')
242 p--;
|
243 krisbash 1.3 #ifdef _PREFAST_
244 #pragma prefast (pop)
245 #endif
|
246 mike 1.1
|
247 krisbash 1.3 p[1] = '\0';
|
248 mike 1.1
249 return MI_TRUE;
250 }
251
252 static MI_Boolean _getHeaderField(
|
253 krisbash 1.3 HttpClient_SR_SocketData* handler,
254 _Inout_ CharPtr* line)
|
255 mike 1.1 {
256 /* expecting Request-Line = Method SP Request-URI SP HTTP-Version CRLF
257 Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
258 */
259 char* name = *line;
260 char* value = NULL;
261 int nameHashCode;
262
263 if (!_getNameValuePair(line, &value, &nameHashCode))
264 return MI_FALSE;
265
|
266 krisbash 1.3 if (nameHashCode == _HashCode('c', 'h', 14) && /*Content-Length*/
|
267 mike 1.1 Strcasecmp(name,"Content-Length") == 0)
268 {
|
269 krisbash 1.3 handler->contentLength = Strtoull(value, NULL, 10);
270 /*if (handler->contentLength > HTTP_MAX_CONTENT)
271 handler->contentBegin = -1;
272 handler->contentEnd = -1;
273 handler->contentTotalLength = -1;
274 return MI_FALSE;*/
|
275 mike 1.1 }
|
276 krisbash 1.3 else if (nameHashCode == _HashCode('t', 'g', 17) && /*Transfer-Encoding*/
|
277 mike 1.1 Strcasecmp(name,"Transfer-Encoding") == 0)
278 {
|
279 krisbash 1.3 handler->contentLength = -1;
280 handler->contentBegin = -1;
281 handler->contentEnd = -1;
282 handler->contentTotalLength = -1;
283 }
284 else if (nameHashCode == _HashCode('c','e',13) && /*Content-Range*/
285 Strcasecmp(name, "Content-Range") == 0)
286 {
287 char* delimptr;
288 char* endptr;
289 handler->contentEnd = -1;
290 handler->contentBegin = (MI_Sint64)Strtoull(value, NULL, 10);
291 delimptr = strchr(value, '-');
292 endptr = strchr(value, '\n');
293 if (delimptr != NULL && (endptr == NULL || endptr > delimptr))
294 handler->contentEnd = Strtoull(++delimptr, NULL, 10);
295 delimptr = strchr(value, '/');
296 if (delimptr != NULL && (endptr == NULL || endptr > delimptr))
297 handler->contentTotalLength = Strtoull(++delimptr, NULL, 10);
298 }
299 if (handler->recvHeaders.sizeHeaders < MI_COUNT(handler->recvHeaderFields))
300 krisbash 1.3 {
301 handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].name = name;
302 handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].value = value;
303 handler->recvHeaders.sizeHeaders++;
|
304 mike 1.1 }
305 else
306 {
|
307 krisbash 1.3 trace_TooManyHttpHeaders(scs(name), scs(value));
|
308 mike 1.1 }
309
310 return MI_TRUE;
311 }
312
313 static MI_Boolean _getChunkSize(
314 const char * line,
315 MI_Uint32* chunkSize)
316 {
317 *chunkSize = 0;
318
|
319 krisbash 1.3 while (*line)
|
320 mike 1.1 {
321 char c = *line;
322
323 if (c >= '0' && c <= '9')
324 *chunkSize = *chunkSize * 16 + (c - '0');
325 else if (c >= 'a' && c <= 'f')
326 *chunkSize = *chunkSize * 16 + (c - 'a' + 10);
327 else if (c >= 'A' && c <= 'F')
328 *chunkSize = *chunkSize * 16 + (c - 'A' + 10);
329 else
330 break;
331
332 line++;
333 }
334
335 return MI_TRUE;
336 }
337
338
339 static MI_Boolean _getRequestLine(
|
340 krisbash 1.3 HttpClient_SR_SocketData* handler,
341 _Inout_ CharPtr* line)
|
342 mike 1.1 {
343 size_t index;
344 /* expecting Request-Line = Method SP Request-URI SP HTTP-Version CRLF
345 Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
346 */
347
348 /* initialize header */
349 handler->recvHeaders.sizeHeaders = 0;
350 handler->recvHeaders.headers = handler->recvHeaderFields;
351
352 /* find http code */
353 {
354 /* skip http version, that is in format
355 HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
356 http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.1
357
358 Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
359 */
|
360 krisbash 1.3 const char* s = *line; /*+ HTTP/1.1<sp>*/
361 size_t skips = 9;
362 for (; skips > 0; s++)
363 {
364 skips--;
365 if (!*s)
366 {
367 return MI_FALSE;
368 }
369 }
|
370 mike 1.1
371 handler->recvHeaders.httpError = Strtoul(s, NULL, 10);
372 }
373
374 /* skip to end of line */
|
375 krisbash 1.3 for (index = 1; (*line)[index] && index < handler->receivedSize; index++)
|
376 mike 1.1 {
|
377 krisbash 1.3 if ((*line)[index-1] == '\r' && (*line)[index] == '\n')
|
378 mike 1.1 {
379 (*line) = (*line) + index + 1;
380 return MI_TRUE;
381 }
382 }
383
384 return MI_FALSE;
385 }
386
387 static MI_Result _Sock_Read(
|
388 krisbash 1.3 HttpClient_SR_SocketData* handler,
|
389 mike 1.1 void* buf,
390 size_t buf_size,
391 size_t* sizeRead)
392 {
393 int res;
|
394 krisbash 1.3 int sslError;
395
396 if (handler->ssl == NULL)
397 {
398 MI_Result res = Sock_Read(handler->base.sock, buf, buf_size, sizeRead);
|
399 mike 1.1
|
400 krisbash 1.3 LOGD2((ZT("_Sock_Read - After regular read. socket: %d, result: %d (%s), bytes read: %u / %u"), handler->base.sock, (int)res, mistrerror(res), (unsigned int)*sizeRead, (unsigned int)buf_size));
401 return res;
402 }
|
403 mike 1.1
404 handler->base.mask &= ~SELECTOR_WRITE;
405 handler->base.mask |= SELECTOR_READ;
406 handler->reverseOperations = MI_FALSE;
407
408 *sizeRead = 0;
409
410 res = SSL_read(handler->ssl, buf, buf_size);
|
411 krisbash 1.3 LOGD2((ZT("_Sock_Read - SSL_Read returned: %d (< 0 for error) / %u bytes read, errno: %d (%s)"), res, (unsigned int)buf_size, errno, strerror(errno)));
412 if (res == 0)
413 {
414 LOGW2((ZT("_Sock_Read - SSL socket connection closed. socket: %d"), handler->base.sock));
|
415 mike 1.1 return MI_RESULT_OK; /* connection closed */
|
416 krisbash 1.3 }
|
417 mike 1.1
|
418 krisbash 1.3 if (res > 0)
|
419 mike 1.1 {
|
420 krisbash 1.3 LOGD2((ZT("_Sock_read - Bytes read: %d"), res));
|
421 mike 1.1 *sizeRead = res;
422 return MI_RESULT_OK; /* ok */
423 }
424
|
425 krisbash 1.3 sslError = SSL_get_error(handler->ssl, res);
426 switch (sslError)
|
427 mike 1.1 {
428 case SSL_ERROR_WANT_WRITE:
429 handler->reverseOperations = MI_TRUE; /* wait until write is allowed */
430 handler->base.mask &= ~SELECTOR_READ;
431 handler->base.mask |= SELECTOR_WRITE;
|
432 krisbash 1.3 LOGD2((ZT("_Sock_Read - SSL_read/accept returned WANT_WRITE")));
|
433 mike 1.1 return MI_RESULT_WOULD_BLOCK;
434
435 case SSL_ERROR_WANT_READ:
|
436 krisbash 1.3 LOGD2((ZT("Sock_Read - SSL_read/accept returned WANT_READ")));
|
437 mike 1.1 return MI_RESULT_WOULD_BLOCK;
438
439 case SSL_ERROR_SYSCALL:
440 if (EAGAIN == errno ||
441 EWOULDBLOCK == errno ||
442 EINPROGRESS == errno)
443 return MI_RESULT_WOULD_BLOCK;
444
|
445 krisbash 1.3 LOGE2((ZT("Sock_Read - SSL_read returned OS error %d (%s)"), errno, strerror(errno)));
446 trace_SSLRead_UnexpectedSysError(errno);
|
447 mike 1.1 break;
448
449 default:
|
450 krisbash 1.3 /* print Open SSL error stack */
|
451 mike 1.1 {
|
452 krisbash 1.3 unsigned long err;
453 while ((err = ERR_get_error()) != 0)
|
454 mike 1.1 {
455 char err_txt[200];
456
|
457 krisbash 1.3 ERR_error_string_n(err, err_txt, sizeof (err_txt));
458 LOGE2((ZT("_Sock_Read - SSL_read returned OpenSSL error: %lu (%s)"), err, err_txt));
|
459 mike 1.1 }
460 }
461 break;
462 }
463 return MI_RESULT_FAILED;
464 }
465
466 static MI_Result _Sock_Write(
|
467 krisbash 1.3 HttpClient_SR_SocketData* handler,
|
468 mike 1.1 void* buf,
469 size_t buf_size,
470 size_t* sizeWritten)
471 {
472 int res;
|
473 krisbash 1.3 int sslError;
|
474 mike 1.1
475 if (!handler->ssl)
|
476 krisbash 1.3 {
477 MI_Result res = Sock_Write(handler->base.sock, buf, buf_size, sizeWritten);
478 LOGD2((ZT("_Sock_Write - Non-SSS write. Sock_Write returned %d (%s). %u / %u bytes sent"), res, mistrerror(res), (unsigned int)*sizeWritten, (unsigned int)buf_size));
479 return res;
480 }
|
481 mike 1.1
482 /* Do not clear READ flag, since 'close' notification
|
483 krisbash 1.3 delivered as READ event */
|
484 krisbash 1.4 handler->base.mask &= ~SELECTOR_READ;
|
485 mike 1.1 handler->base.mask |= SELECTOR_WRITE;
486 handler->reverseOperations = MI_FALSE;
487
488 *sizeWritten = 0;
489
490 if (handler->connectDone)
491 {
492 res = SSL_write(handler->ssl, buf, buf_size);
|
493 krisbash 1.3 LOGD2((ZT("_Sock_Write - SSL_write using socket %d returned %d (< 0 for error) / %u bytes written, errno: %d (%s)"), handler->base.sock, res, (unsigned int)buf_size, errno, strerror(errno)));
|
494 mike 1.1 }
495 else
496 {
497 res = SSL_connect(handler->ssl);
|
498 krisbash 1.3 LOGD2((ZT("_Sock_Write - SSL connect using socket %d returned result: %d, errno: %d (%s)"), handler->base.sock, res, errno, strerror(errno)));
499 if (res > 0)
|
500 mike 1.1 {
|
501 krisbash 1.3 /* we are done with accept */
|
502 mike 1.1 handler->connectDone = MI_TRUE;
503 return _Sock_Write(handler,buf,buf_size,sizeWritten);
504 }
505 /* perform regular error checking */
506 }
507
508
|
509 krisbash 1.3 if (res == 0)
510 {
511 LOGW2((ZT("_Sock_Write - SSL socket connection closed")));
|
512 mike 1.1 return MI_RESULT_OK; /* connection closed */
|
513 krisbash 1.3 }
|
514 mike 1.1
|
515 krisbash 1.3 if (res > 0)
|
516 mike 1.1 {
517 *sizeWritten = res;
|
518 krisbash 1.3 LOGD2((ZT("_Sock_Write - SSL socket successful write of %d / %u bytes"), res, (unsigned int)buf_size));
|
519 mike 1.1 return MI_RESULT_OK; /* ok */
520 }
521
|
522 krisbash 1.3 sslError = SSL_get_error(handler->ssl, res);
523 switch (sslError)
|
524 mike 1.1 {
525 case SSL_ERROR_WANT_WRITE:
|
526 krisbash 1.3 LOGD2((ZT("_Sock_Write - SSL_write/connect returned WANT_WRITE")));
|
527 mike 1.1 return MI_RESULT_WOULD_BLOCK;
528
529 case SSL_ERROR_WANT_READ:
|
530 krisbash 1.3 LOGD2((ZT("_Sock_Write - SSL_write/connect returned WANT_READ")));
|
531 mike 1.1 handler->reverseOperations = MI_TRUE; /* wait until write is allowed */
532 handler->base.mask |= SELECTOR_READ;
|
533 krisbash 1.4 handler->base.mask &= ~SELECTOR_WRITE;
|
534 mike 1.1 return MI_RESULT_WOULD_BLOCK;
535
536 case SSL_ERROR_SYSCALL:
537 if (EAGAIN == errno ||
538 EWOULDBLOCK == errno ||
539 EINPROGRESS == errno)
|
540 krisbash 1.3 {
541 LOGD2((ZT("_Sock_Write - Returning WOULD_BLOCK. errno: %d (%s)"), errno, strerror(errno)));
|
542 mike 1.1 return MI_RESULT_WOULD_BLOCK;
|
543 krisbash 1.3 }
544
545 LOGE2((ZT("_Sock_Write - SSL_write/connect returned unexpected OS error %d (%s)"), errno, strerror(errno)));
546 trace_SSLWrite_UnexpectedSysError(errno);
547 break;
|
548 mike 1.1
|
549 krisbash 1.3 case SSL_ERROR_SSL:
550 LOGE2((ZT("_Sock_Write - SSL_write/connect returned OpenSSL error %d (%s)"), sslError, ERR_error_string(sslError, NULL)));
|
551 mike 1.1 break;
552
553 default:
|
554 krisbash 1.3 LOGD2((ZT("_Sock_Write - SSL_write/connect returned uncategorized OpenSSL error: %d"), res));
|
555 mike 1.1 break;
556 }
|
557 krisbash 1.3
|
558 mike 1.1 return MI_RESULT_FAILED;
559 }
560
561 static Http_CallbackResult _ReadHeader(
|
562 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
563 mike 1.1 {
564 char* buf;
565 char* currentLine;
566 char* data;
|
567 krisbash 1.3 size_t contentSize;
|
568 mike 1.1 size_t buf_size, received, index;
569 MI_Result r;
570 MI_Boolean fullHeaderReceived = MI_FALSE;
571
572 /* are we done with header? */
573 if (handler->recvingState != RECV_STATE_HEADER)
574 return PRT_CONTINUE;
575
|
576 krisbash 1.3 buf = handler->recvBuffer + handler->receivedSize;
577 buf_size = handler->recvBufferSize - handler->receivedSize;
|
578 mike 1.1 received = 0;
579
580 r = _Sock_Read(handler, buf, buf_size, &received);
|
581 krisbash 1.3 LOGD2((ZT("_ReadHeader - Begin. _Sock_read result: %d (%s), socket: %d, %u / %u bytes read, reverse: %d"), (int)r, mistrerror(r), (int)handler->base.sock, (unsigned int)received, (unsigned int)buf_size, (int)handler->reverseOperations));
|
582 mike 1.1
|
583 krisbash 1.3 if (r == MI_RESULT_OK && 0 == received)
584 {
585 LOGW2((ZT("_ReadHeader - 0 bytes received without error. Socket closed?")));
586 return PRT_RETURN_FALSE; /* connection closed */
587 }
|
588 mike 1.1
|
589 krisbash 1.3 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
590 {
591 LOGE2((ZT("_ReadHeader - Error %d (%s)"), r, mistrerror(r)));
|
592 mike 1.1 return PRT_RETURN_FALSE;
|
593 krisbash 1.3 }
|
594 mike 1.1
|
595 krisbash 1.3 if (received == 0)
596 {
597 LOGD2((ZT("_ReadHeader - 0 bytes received. Waiting...")));
|
598 mike 1.1 return PRT_RETURN_TRUE;
|
599 krisbash 1.3 }
|
600 mike 1.1
|
601 krisbash 1.3 handler->receivedSize += received;
|
602 mike 1.1
603 /* check header */
|
604 krisbash 1.3 LOGD2((ZT("_ReadHeader - Received buffer: %s"), buf));
|
605 mike 1.1
606 /* did we get full header? */
607 buf = handler->recvBuffer;
|
608 krisbash 1.3 LOGD2((ZT("_ReadHeader - Checking for full header...")));
609 for ( index = 3; index < handler->receivedSize; index++ )
|
610 mike 1.1 {
|
611 krisbash 1.3 _Analysis_assume_(handler->recvBufferSize > 3);
|
612 mike 1.1 if (buf[index-3] == '\r' && buf[index-1] == '\r' &&
613 buf[index-2] == '\n' && buf[index] == '\n' )
614 {
615 fullHeaderReceived = MI_TRUE;
|
616 krisbash 1.3 LOGD2((ZT("_ReadHeader - Full header has been received")));
|
617 mike 1.1 break;
618 }
619 }
620
|
621 krisbash 1.3 if (!fullHeaderReceived)
|
622 mike 1.1 {
|
623 krisbash 1.3 if (handler->receivedSize < handler->recvBufferSize)
624 {
625 LOGD2((ZT("_ReadHeader - Full header not received. Waiting...")));
|
626 mike 1.1 return PRT_RETURN_TRUE; /* continue reading */
|
627 krisbash 1.3 }
|
628 mike 1.1
|
629 krisbash 1.3 if (handler->recvBufferSize < MAX_HEADER_SIZE)
|
630 mike 1.1 {
|
631 krisbash 1.3 LOGD2((ZT("_ReadHeader - Reallocating buffer...")));
632 buf = PAL_Realloc(handler->recvBuffer, handler->recvBufferSize * 2);
|
633 mike 1.1
634 if (!buf)
|
635 krisbash 1.3 {
636 LOGE2((ZT("_ReadHeader - Cannot allocate memory for larger header")));
|
637 mike 1.1 return PRT_RETURN_FALSE;
|
638 krisbash 1.3 }
|
639 mike 1.1
640 handler->recvBufferSize *= 2;
641 handler->recvBuffer = buf;
|
642 krisbash 1.3 LOGD2((ZT("_ReadHeader - Going recursive...")));
|
643 mike 1.1 return _ReadHeader(handler);
644 }
645 else
646 {
|
647 krisbash 1.3 /* Http header is too big - drop connection */
648 trace_HttpHeaderIsTooBig();
649 LOGE2((ZT("_ReadHeader - HTTP header is too big. Dropping connection")));
|
650 mike 1.1 return PRT_RETURN_FALSE;
651 }
652 }
653
654 /* consume data */
655 currentLine = buf;
656 data = buf + index + 1; /* pointer to data in case we got some */
657
658 if (!_getRequestLine(handler, ¤tLine))
|
659 krisbash 1.3 {
660 LOGE2((ZT("_ReadHeader - Cannot find request line in HTTP header")));
|
661 mike 1.1 return PRT_RETURN_FALSE;
|
662 krisbash 1.3 }
|
663 mike 1.1
|
664 krisbash 1.3 while ((data - currentLine) > 3)
|
665 mike 1.1 {
666 if (!_getHeaderField(handler, ¤tLine))
|
667 krisbash 1.3 {
668 LOGE2((ZT("_ReadHeader - Cannot find HTTP header field")));
|
669 mike 1.1 return PRT_RETURN_FALSE;
|
670 krisbash 1.3 }
|
671 mike 1.1 }
672
673 /* Check if we have to deal with chunked-encoded data */
674 if (handler->contentLength < 0)
675 {
|
676 krisbash 1.3 handler->receivedSize -= index + 1;
|
677 mike 1.1
678 /* Invoke user's callback with header information */
679 {
680 HttpClient* self = (HttpClient*)handler->base.data;
681
|
682 krisbash 1.4 if (!(*self->callbackOnResponse)(self, self->callbackData, &handler->recvHeaders,
|
683 mike 1.1 handler->contentLength, handler->contentLength == 0, 0))
|
684 krisbash 1.3 {
685 LOGD2((ZT("_ReadHeader - On response callback for chunked data header failed")));
|
686 mike 1.1 return PRT_RETURN_FALSE;
|
687 krisbash 1.3 }
|
688 mike 1.1 }
689
690 /* remove consumed header part */
|
691 krisbash 1.3 memmove(handler->recvBuffer, data, handler->receivedSize);
|
692 mike 1.1
693 handler->recvingState = RECV_STATE_CHUNKHEADER;
694 return PRT_CONTINUE;
695 }
696
|
697 krisbash 1.3 contentSize = (size_t)handler->contentLength;
698 if (handler->headVerb)
699 {
700 LOGD2((ZT("_ReadHeader - HEAD response received. Download will contain %u bytes"), (unsigned int)contentSize));
701 contentSize = 0;
702 }
703
|
704 krisbash 1.4 size_t allocSize = 0;
705 if (SizeTAdd(sizeof(Page), contentSize, &allocSize) == S_OK &&
706 SizeTAdd(allocSize, 1, &allocSize) == S_OK)
707 {
708 /* Allocate zero-terminated buffer */
709 handler->recvPage = (Page*)PAL_Malloc(allocSize);
710 }
711 else
712 {
713 // Overflow
714 return PRT_RETURN_FALSE;
715 }
|
716 mike 1.1
|
717 krisbash 1.3 if (handler->recvPage == NULL)
718 {
719 LOGD2((ZT("_ReadHeader - Cannot allocate memory for received page")));
|
720 mike 1.1 return PRT_RETURN_FALSE;
|
721 krisbash 1.3 }
722 ((char*)(handler->recvPage + 1))[contentSize] = '\0';
|
723 mike 1.1
|
724 krisbash 1.3 handler->recvPage->u.s.size = (unsigned int)contentSize;
|
725 mike 1.1 handler->recvPage->u.s.next = 0;
|
726 krisbash 1.3 handler->receivedSize -= index + 1;
|
727 mike 1.1
|
728 krisbash 1.4 /* Verify that we have not more than 'content-length' bytes in buffer left
|
729 mike 1.1 If we have more, assuming http client is invalid and drop connection */
|
730 krisbash 1.3 if (handler->receivedSize > contentSize)
|
731 mike 1.1 {
|
732 krisbash 1.3 trace_HttpPayloadIsBiggerThanContentLength();
733 LOGE2((ZT("_ReadHeader - HTTP payload is bigger than content-length (%u > %u bytes)"), (unsigned int)handler->receivedSize, (unsigned int)contentSize));
|
734 mike 1.1 return PRT_RETURN_FALSE;
735 }
736
|
737 krisbash 1.3 if (handler->receivedSize != 0)
738 memcpy(handler->recvPage + 1, data, handler->receivedSize);
|
739 mike 1.1 handler->recvingState = RECV_STATE_CONTENT;
740
741 /* Invoke user's callback with header information */
742 {
743 HttpClient* self = (HttpClient*)handler->base.data;
744
|
745 krisbash 1.4 if (!(*self->callbackOnResponse)(self, self->callbackData, &handler->recvHeaders,
|
746 mike 1.1 handler->contentLength, handler->contentLength == 0, 0))
|
747 krisbash 1.3 {
748 LOGE2((ZT("_ReadHeader - On response callback for header failed")));
|
749 mike 1.1 return PRT_RETURN_FALSE;
|
750 krisbash 1.3 }
|
751 mike 1.1 }
752
|
753 krisbash 1.3 LOGD2((ZT("_ReadHeader - OK exit")));
|
754 mike 1.1 return PRT_CONTINUE;
755 }
756
757 static Http_CallbackResult _ReadData(
|
758 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
759 mike 1.1 {
|
760 krisbash 1.3 /* HttpClient* self = (HttpClient*)handler->base.data; */
|
761 mike 1.1 char* buf;
762 size_t buf_size, received;
763 MI_Result r;
764
765 /* are we in the right state? */
766 if (handler->recvingState != RECV_STATE_CONTENT)
767 return PRT_RETURN_FALSE;
768
|
769 krisbash 1.3 LOGD2((ZT("_ReadData - Begin. Head? %d"), handler->headVerb));
770 if (!handler->headVerb)
771 {
772 buf = (char*)(handler->recvPage + 1) + handler->receivedSize;
773 buf_size = (size_t)(handler->contentLength - handler->receivedSize);
774 received = 0;
775
776 if (buf_size != 0)
777 {
778 r = _Sock_Read(handler, buf, buf_size, &received);
779 LOGD2((ZT("_ReadData - _Sock_Read result: %d (%s), socket: %d, recv: %u"), (int)r, mistrerror(r), (int)handler->base.sock, (unsigned int)received));
|
780 mike 1.1
|
781 krisbash 1.3 if (r == MI_RESULT_OK && 0 == received)
782 return PRT_RETURN_FALSE; /* connection closed */
|
783 mike 1.1
|
784 krisbash 1.3 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
785 return PRT_RETURN_FALSE;
|
786 mike 1.1
|
787 krisbash 1.3 handler->receivedSize += received;
|
788 mike 1.1
|
789 krisbash 1.3 LOGD2((ZT("_RequestCallback - Called _ReadData. %d / %d bytes read"), (int)handler->receivedSize, (int)handler->contentLength));
|
790 mike 1.1
|
791 krisbash 1.3 if (handler->contentLength > 0 && handler->receivedSize < (size_t)handler->contentLength)
792 { /* assume 500 bytes per millisecond transmission */
793 /* wait to avoid spinning on _Sock_Read */
794 unsigned int bytesLeft = (unsigned int)handler->contentLength - (unsigned int)handler->receivedSize;
795 unsigned long msec = (unsigned long)(bytesLeft / 500 + 1);
|
796 mike 1.1
|
797 krisbash 1.3 Sleep_Milliseconds(msec);
798 }
799 }
|
800 mike 1.1
|
801 krisbash 1.3 /* did we get all data? */
802 LOGD2((ZT("_ReadData - Received size: %d / %d"), (int)handler->receivedSize, (int)handler->contentLength));
803 if (handler->receivedSize != (size_t)handler->contentLength)
804 return PRT_RETURN_TRUE;
805 }
|
806 krisbash 1.4
|
807 mike 1.1 /* Invoke user's callback with header information */
808 {
809 HttpClient* self = (HttpClient*)handler->base.data;
|
810 krisbash 1.3 MI_Boolean lastChunk = MI_TRUE;
|
811 mike 1.1
|
812 krisbash 1.3 if (handler->contentEnd >= 0 &&
813 handler->contentEnd + 1 < handler->contentTotalLength)
814 {
815 lastChunk = MI_FALSE;
816 }
817
|
818 krisbash 1.4 if (!(*self->callbackOnResponse)(self, self->callbackData, 0,
|
819 krisbash 1.3 handler->contentLength, lastChunk, &handler->recvPage))
|
820 mike 1.1 return PRT_RETURN_FALSE;
821
822 /* status callback */
823 handler->status = MI_RESULT_OK;
824 (*self->callbackOnStatus)(
|
825 krisbash 1.4 self,
826 self->callbackData,
|
827 krisbash 1.3 MI_RESULT_OK);
|
828 mike 1.1 }
829
|
830 krisbash 1.3 if (handler->recvPage != NULL)
831 {
832 LOGD2((ZT("_ReadData - Freeing recvPage. socket: %d"), (int)handler->base.sock));
833 PAL_Free(handler->recvPage);
834 }
|
835 mike 1.1
|
836 krisbash 1.3 handler->recvPage = NULL;
837 handler->receivedSize = 0;
|
838 mike 1.1 memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
839 handler->recvingState = RECV_STATE_HEADER;
|
840 krisbash 1.3 LOGD2((ZT("_ReadData - OK exit")));
|
841 mike 1.1 return PRT_CONTINUE;
842 }
843
844 static Http_CallbackResult _ReadChunkHeader(
|
845 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
846 mike 1.1 {
847 char* buf;
848 char* currentLine;
849 char* data;
850 size_t buf_size, received, index;
851 MI_Result r;
852 MI_Boolean fullHeaderReceived = MI_FALSE;
853 MI_Uint32 chunkSize = 0;
854 MI_Boolean connectionClosed = MI_FALSE;
855
856 /* are we done with header? */
857 if (handler->recvingState != RECV_STATE_CHUNKHEADER)
858 return PRT_CONTINUE;
859
|
860 krisbash 1.3 buf = handler->recvBuffer + handler->receivedSize;
861 buf_size = handler->recvBufferSize - handler->receivedSize;
|
862 mike 1.1 received = 0;
863
864 r = _Sock_Read(handler, buf, buf_size, &received);
865
|
866 krisbash 1.3 if (r == MI_RESULT_OK && 0 == received)
|
867 mike 1.1 {
868 if (!handler->recvBufferSize)
|
869 krisbash 1.3 return PRT_RETURN_FALSE; /* connection closed */
|
870 mike 1.1
871 connectionClosed = MI_TRUE;
872 }
873
|
874 krisbash 1.3 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
|
875 mike 1.1 return PRT_RETURN_FALSE;
876
877 if (!received && !handler->recvBufferSize)
878 return PRT_RETURN_TRUE;
879
|
880 krisbash 1.3 handler->receivedSize += received;
|
881 mike 1.1
882 /* did we get full header? */
883 buf = handler->recvBuffer;
|
884 krisbash 1.3
885 _Analysis_assume_(handler->recvBufferSize > 2);
886 for (index = 1; index < handler->receivedSize && buf[index]; index++)
|
887 mike 1.1 {
888 if (buf[index-1] == '\r' && buf[index] == '\n' )
889 {
890 fullHeaderReceived = MI_TRUE;
891 break;
892 }
893 }
894
|
895 krisbash 1.3 if (!fullHeaderReceived)
|
896 mike 1.1 {
897 if (connectionClosed)
|
898 krisbash 1.3 return PRT_RETURN_FALSE; /* connection closed */
|
899 mike 1.1
|
900 krisbash 1.3 if (handler->receivedSize < handler->recvBufferSize)
|
901 mike 1.1 return PRT_RETURN_TRUE; /* continue reading */
902
|
903 krisbash 1.3 if (handler->recvBufferSize < MAX_HEADER_SIZE)
|
904 mike 1.1 {
|
905 krisbash 1.3 buf = PAL_Realloc(handler->recvBuffer, handler->recvBufferSize * 2);
|
906 mike 1.1
907 if (!buf)
908 return PRT_RETURN_FALSE;
909
910 handler->recvBufferSize *= 2;
911 handler->recvBuffer = buf;
912 return _ReadChunkHeader(handler);
913 }
914 else
915 {
916 /* http chunk header is too big - drop connection */
|
917 krisbash 1.3 trace_HttpChunkHeaderIsTooBig();
|
918 mike 1.1 return PRT_RETURN_FALSE;
919 }
920 }
921
922 /* consume data */
923 currentLine = buf;
924 data = buf + index + 1; /* pointer to data in case we got some */
925
926 if (!_getChunkSize(currentLine, &chunkSize))
927 return PRT_RETURN_FALSE;
928
929 if (0 == chunkSize)
930 {
931 /* last chunk received */
932
933 /* Invoke user's callback with header information */
934 {
935 HttpClient* self = (HttpClient*)handler->base.data;
936
|
937 krisbash 1.3 if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
|
938 mike 1.1 handler->contentLength, MI_TRUE, 0))
939 return PRT_RETURN_FALSE;
940
941 /* status callback */
942 handler->status = MI_RESULT_OK;
943 (*self->callbackOnStatus)(
|
944 krisbash 1.3 self,
945 self->callbackData,
946 MI_RESULT_OK);
|
947 mike 1.1 }
948
949 /* clean up state */
950 handler->recvPage = 0;
|
951 krisbash 1.3 handler->receivedSize = 0;
|
952 mike 1.1 memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
953 handler->recvingState = RECV_STATE_HEADER;
954
955 if (connectionClosed)
|
956 krisbash 1.3 return PRT_RETURN_FALSE; /* connection closed */
|
957 mike 1.1
958 return PRT_CONTINUE;
959 }
960
|
961 krisbash 1.4 size_t allocSize = 0;
962 if (SizeTAdd(sizeof(Page), (size_t)chunkSize, &allocSize) == S_OK &&
963 SizeTAdd(allocSize, 2 /*CR-LF*/ + 1 /* \0 */, &allocSize) == S_OK)
964 {
965 /* Allocate zero-terminated buffer */
966 handler->recvPage = (Page*)PAL_Malloc(allocSize);
967 }
968 else
969 {
970 // Overflow
971 return PRT_RETURN_FALSE;
972 }
|
973 mike 1.1
974 if (!handler->recvPage)
975 return PRT_RETURN_FALSE;
976
977 ((char*)(handler->recvPage + 1))[chunkSize+2] = 0;
978
979 handler->recvPage->u.s.size = (unsigned int)chunkSize;
980 handler->recvPage->u.s.next = 0;
981
982 /* subtract header size */
|
983 krisbash 1.3 handler->receivedSize -= index + 1;
|
984 mike 1.1
985 /* in case of small chunks we may receive more than one chunk already */
|
986 krisbash 1.3 if (handler->receivedSize > (size_t)(chunkSize+2))
|
987 mike 1.1 {
988 /* copy page size to page */
|
989 krisbash 1.3 memcpy(handler->recvPage + 1, data, chunkSize+2);
|
990 mike 1.1
991 /* notify user */
992 {
993 HttpClient* self = (HttpClient*)handler->base.data;
994
|
995 krisbash 1.3 if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
|
996 mike 1.1 handler->contentLength, MI_FALSE, &handler->recvPage))
997 return PRT_RETURN_FALSE;
998
999 if (handler->recvPage)
|
1000 krisbash 1.3 PAL_Free(handler->recvPage);
|
1001 mike 1.1
1002 handler->recvPage = 0;
1003 }
1004
1005 /* remove consumed part */
|
1006 krisbash 1.3 memmove(handler->recvBuffer, data + chunkSize+2, handler->receivedSize - (chunkSize+2));
1007 handler->receivedSize -= (chunkSize+2);
|
1008 mike 1.1
1009 /* consume next chunk */
1010 return _ReadChunkHeader(handler);
1011 }
1012
|
1013 krisbash 1.3 memcpy(handler->recvPage + 1, data, handler->receivedSize);
|
1014 mike 1.1 handler->recvingState = RECV_STATE_CHUNKDATA;
1015
1016 if (connectionClosed)
|
1017 krisbash 1.3 return PRT_RETURN_FALSE; /* connection closed */
|
1018 mike 1.1
1019 return PRT_CONTINUE;
1020 }
1021 static Http_CallbackResult _ReadChunkData(
|
1022 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
1023 mike 1.1 {
1024 //HttpClient* self = (HttpClient*)handler->base.data;
1025 char* buf;
1026 size_t buf_size, received;
1027 MI_Result r;
1028
1029 /* are we in the right state? */
1030 if (handler->recvingState != RECV_STATE_CHUNKDATA)
1031 return PRT_RETURN_FALSE;
1032
|
1033 krisbash 1.3 buf = ((char*)(handler->recvPage + 1)) + handler->receivedSize;
1034 buf_size = (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */ - handler->receivedSize);
|
1035 mike 1.1 received = 0;
1036
1037 if (buf_size)
1038 {
1039 r = _Sock_Read(handler, buf, buf_size, &received);
1040
|
1041 krisbash 1.3 if (r == MI_RESULT_OK && 0 == received)
1042 return PRT_RETURN_FALSE; /* connection closed */
|
1043 mike 1.1
|
1044 krisbash 1.3 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
|
1045 mike 1.1 return PRT_RETURN_FALSE;
1046
|
1047 krisbash 1.3 handler->receivedSize += received;
|
1048 mike 1.1 }
1049
|
1050 krisbash 1.3 if (handler->receivedSize != (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */))
1051 return PRT_RETURN_TRUE;
|
1052 mike 1.1
1053 /* Invoke user's callback with header information */
1054 {
1055 HttpClient* self = (HttpClient*)handler->base.data;
1056
|
1057 krisbash 1.3 if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
|
1058 mike 1.1 handler->contentLength, MI_FALSE, &handler->recvPage))
1059 return PRT_RETURN_FALSE;
1060
1061 }
1062
1063 if (handler->recvPage)
|
1064 krisbash 1.3 PAL_Free(handler->recvPage);
|
1065 mike 1.1
1066 handler->recvPage = 0;
|
1067 krisbash 1.3 handler->receivedSize = 0;
|
1068 mike 1.1 memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
1069 handler->recvingState = RECV_STATE_CHUNKHEADER;
1070 return PRT_CONTINUE;
1071 }
1072
1073 static Http_CallbackResult _WriteHeader(
|
1074 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
1075 mike 1.1 {
1076 char* buf;
1077 size_t buf_size, sent;
1078 MI_Result r;
1079
1080 /* Do we have any data to send? */
1081 if (!handler->sendHeader)
1082 return PRT_RETURN_TRUE;
1083
1084 /* are we done with header? */
1085 if (handler->sendingState == RECV_STATE_CONTENT)
1086 return PRT_CONTINUE;
1087
|
1088 krisbash 1.3 LOGD2((ZT("_WriteHeader - Begin")));
1089
|
1090 mike 1.1 buf = ((char*)(handler->sendHeader + 1)) + handler->sentSize;
1091 buf_size = handler->sendHeader->u.s.size - handler->sentSize;
1092 sent = 0;
1093
1094 r = _Sock_Write(handler, buf, buf_size, &sent);
|
1095 krisbash 1.3 LOGD2((ZT("_WriteHeader - _Sock_Write result: %d (%s), socket: %d, sent: %d"), (int)r, mistrerror(r), (int)handler->base.sock, (int)sent));
|
1096 mike 1.1
|
1097 krisbash 1.3 if (r == MI_RESULT_OK && 0 == sent)
1098 {
1099 LOGE2((ZT("_WriteHeader - Connection closed")));
1100 return PRT_RETURN_FALSE; /* connection closed */
1101 }
|
1102 mike 1.1
|
1103 krisbash 1.3 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1104 {
1105 LOGE2((ZT("_WriteHeader - _Sock_Write returned error: %d (%s)"), (int)r, mistrerror(r)));
|
1106 mike 1.1 return PRT_RETURN_FALSE;
|
1107 krisbash 1.3 }
|
1108 mike 1.1
1109 handler->sentSize += sent;
|
1110 krisbash 1.3 handler->headVerb = buf_size > 4 && Strncasecmp(buf, "HEAD", 4) == 0;
|
1111 mike 1.1
|
1112 krisbash 1.3 /* did we send all data? */
1113 if (handler->sentSize != handler->sendHeader->u.s.size)
1114 {
1115 LOGD2((ZT("_WriteHeader - Partial write. %u sent this time, %u / %d written, result: %d (%s)"), (unsigned int)sent, (unsigned int)handler->sentSize, (unsigned int)handler->sendHeader->u.s.size, r, mistrerror(r)));
1116 return PRT_RETURN_TRUE;
1117 }
|
1118 mike 1.1
|
1119 krisbash 1.3 PAL_Free(handler->sendHeader);
|
1120 mike 1.1 handler->sendHeader = 0;
1121 handler->sentSize = 0;
1122 handler->sendingState = RECV_STATE_CONTENT;
1123
|
1124 krisbash 1.3 LOGD2((ZT("_WriteHeader - OK exit")));
|
1125 mike 1.1 return PRT_CONTINUE;
1126 }
1127
1128 static Http_CallbackResult _WriteData(
|
1129 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
1130 mike 1.1 {
1131 char* buf;
1132 size_t buf_size, sent;
1133 MI_Result r;
1134
|
1135 krisbash 1.3 LOGD2((ZT("_WriteData - Begin")));
|
1136 mike 1.1 /* are we in the right state? */
1137 if (handler->sendingState != RECV_STATE_CONTENT)
|
1138 krisbash 1.3 {
1139 LOGE2((ZT("_WriteData - Wrong state. state: %d"), handler->sendingState));
|
1140 mike 1.1 return PRT_RETURN_FALSE;
|
1141 krisbash 1.3 }
|
1142 mike 1.1
1143 if (!handler->sendPage)
1144 { /* no content*/
1145 handler->sentSize = 0;
1146 handler->sendingState = RECV_STATE_HEADER;
1147 handler->base.mask &= ~SELECTOR_WRITE;
1148 handler->base.mask |= SELECTOR_READ;
1149
|
1150 krisbash 1.3 LOGW2((ZT("_WriteData - Content is empty. Continuing")));
|
1151 mike 1.1 return PRT_CONTINUE;
1152 }
1153
1154 buf = ((char*)(handler->sendPage + 1)) + handler->sentSize;
1155 buf_size = handler->sendPage->u.s.size - handler->sentSize;
1156 sent = 0;
1157
1158 r = _Sock_Write(handler, buf, buf_size, &sent);
|
1159 krisbash 1.3 LOGD2((ZT("_WriteData - HTTPClient sent %u / %u bytes with result %d (%s)"), (unsigned int)sent, (unsigned int)buf_size, (int)r, mistrerror(r)));
|
1160 mike 1.1
|
1161 krisbash 1.3 if (r == MI_RESULT_OK && 0 == sent)
1162 {
1163 LOGE2((ZT("_WriteData exit. Connection closed")));
1164 return PRT_RETURN_FALSE; /* connection closed */
1165 }
|
1166 mike 1.1
|
1167 krisbash 1.3 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1168 {
1169 LOGE2((ZT("_WriteData exit - Error: %d (%s)"), r, mistrerror(r)));
|
1170 mike 1.1 return PRT_RETURN_FALSE;
|
1171 krisbash 1.3 }
|
1172 mike 1.1
1173 handler->sentSize += sent;
1174
|
1175 krisbash 1.3 /* did we send all data? */
|
1176 mike 1.1
|
1177 krisbash 1.3 if (handler->sentSize != handler->sendPage->u.s.size)
1178 {
1179 LOGD2((ZT("_WriteData - Exit. Partial write. %u / %u bytes written"), (unsigned int)handler->sentSize, (unsigned int)handler->sendPage->u.s.size));
|
1180 mike 1.1 return PRT_RETURN_TRUE;
|
1181 krisbash 1.3 }
1182
1183 LOGD2((ZT("_WriteData - %u / %u bytes sent"), (unsigned int)handler->sentSize, (unsigned int)handler->sendPage->u.s.size));
1184 PAL_Free(handler->sendPage);
1185 handler->sendPage = NULL;
|
1186 mike 1.1 handler->sentSize = 0;
1187 handler->sendingState = RECV_STATE_HEADER;
1188 handler->base.mask &= ~SELECTOR_WRITE;
1189 handler->base.mask |= SELECTOR_READ;
1190
|
1191 krisbash 1.3 LOGD2((ZT("_WriteData - OK exit. returning: %d"), PRT_CONTINUE));
1192
|
1193 mike 1.1 return PRT_CONTINUE;
1194 }
1195
1196 static MI_Boolean _RequestCallbackRead(
|
1197 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
1198 mike 1.1 {
1199 switch (_ReadHeader(handler))
1200 {
1201 case PRT_CONTINUE: break;
1202 case PRT_RETURN_TRUE: return MI_TRUE;
1203 case PRT_RETURN_FALSE: return MI_FALSE;
1204 }
1205
1206 if (handler->recvingState == RECV_STATE_CONTENT)
1207 {
1208 switch (_ReadData(handler))
1209 {
1210 case PRT_CONTINUE: break;
1211 case PRT_RETURN_TRUE: return MI_TRUE;
1212 case PRT_RETURN_FALSE: return MI_FALSE;
1213 }
1214 }
1215
1216 if (handler->recvingState == RECV_STATE_CHUNKHEADER)
1217 {
1218 switch (_ReadChunkHeader(handler))
1219 mike 1.1 {
1220 case PRT_CONTINUE: break;
1221 case PRT_RETURN_TRUE: return MI_TRUE;
1222 case PRT_RETURN_FALSE: return MI_FALSE;
1223 }
1224 }
1225 if (handler->recvingState == RECV_STATE_CHUNKDATA)
1226 {
1227 switch (_ReadChunkData(handler))
1228 {
1229 case PRT_CONTINUE: break;
1230 case PRT_RETURN_TRUE: return MI_TRUE;
1231 case PRT_RETURN_FALSE: return MI_FALSE;
1232 }
1233 }
1234
1235 return MI_TRUE;
1236 }
1237
1238 static MI_Boolean _RequestCallbackWrite(
|
1239 krisbash 1.3 HttpClient_SR_SocketData* handler)
|
1240 mike 1.1 {
1241 switch (_WriteHeader(handler))
1242 {
1243 case PRT_CONTINUE: break;
1244 case PRT_RETURN_TRUE: return MI_TRUE;
1245 case PRT_RETURN_FALSE: return MI_FALSE;
1246 }
1247
1248 switch (_WriteData(handler))
1249 {
1250 case PRT_CONTINUE: break;
1251 case PRT_RETURN_TRUE: return MI_TRUE;
1252 case PRT_RETURN_FALSE: return MI_FALSE;
1253 }
1254 return MI_TRUE;
1255 }
1256
1257
1258 static MI_Boolean _RequestCallback(
1259 Selector* sel,
1260 Handler* handlerIn,
|
1261 krisbash 1.3 MI_Uint32 mask,
|
1262 mike 1.1 MI_Uint64 currentTimeUsec)
1263 {
|
1264 krisbash 1.3 HttpClient_SR_SocketData* handler = (HttpClient_SR_SocketData*)handlerIn;
1265 MI_UNUSED(sel);
|
1266 mike 1.1
|
1267 krisbash 1.3 if (((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||
1268 ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations))
|
1269 mike 1.1 {
1270 if (!_RequestCallbackRead(handler))
|
1271 krisbash 1.3 {
1272 LOGE2((ZT("_RequestCallback - RequestCallbackRead failed")));
|
1273 mike 1.1 return MI_FALSE;
|
1274 krisbash 1.3 }
1275 LOGD2((ZT("_RequestCallback - Called _RequestCallbackRead. %u / %u bytes read"), (unsigned int)handler->receivedSize, handler->recvPage == NULL ? 0 : (unsigned int)handler->recvPage->u.s.size));
|
1276 mike 1.1 }
1277
|
1278 krisbash 1.3 if (((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||
1279 ((mask & SELECTOR_READ) != 0 && handler->reverseOperations))
|
1280 mike 1.1 {
1281 if (!_RequestCallbackWrite(handler))
|
1282 krisbash 1.3 {
1283 LOGE2((ZT("_RequestCallback - _RequestCallbackWrite failed")));
|
1284 mike 1.1 return MI_FALSE;
|
1285 krisbash 1.3 }
1286 LOGD2((ZT("_RequestCallback - Called _RequestCallbackWrite. %u / %u bytes sent"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
1287 while (handler->sendPage != NULL && handler->sentSize < handler->sendPage->u.s.size)
1288 { /* assume 500 bytes per millisecond transmission */
1289 /* wait after to avoid spinning too much on _WriteData */
1290 unsigned int bytesLeft = (unsigned int)handler->sendPage->u.s.size - (unsigned int)handler->sentSize;
1291 unsigned long msec = (unsigned long)(bytesLeft / 500 + 1);
1292
1293 LOGD2((ZT("_RequestCallback - Called _WriteData. %u / %u bytes sent"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
1294 if (_WriteData(handler) == MI_FALSE)
1295 {
1296 LOGE2((ZT("_RequestCallback - _WriteData failed")));
1297 return MI_FALSE;
1298 }
1299 LOGD2((ZT("_RequestCallback - Called _WriteData. %u bytes written, %u bytes left"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
1300 Sleep_Milliseconds(msec);
1301 }
1302 LOGD2((ZT("_RequestCallback - Called _RequestCallbackWrite. %u / %u bytes sent"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
|
1303 mike 1.1 }
|
1304 krisbash 1.4
|
1305 mike 1.1 /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */
1306 if (mask & (SELECTOR_READ | SELECTOR_WRITE))
1307 {
1308 handler->base.fireTimeoutAt = currentTimeUsec + handler->timeoutUsec;
1309 }
1310
|
1311 krisbash 1.3 /* Close connection by timeout */
1312 if ((mask & SELECTOR_TIMEOUT) != 0)
|
1313 mike 1.1 {
|
1314 krisbash 1.3 if (handler->status != MI_RESULT_OK)
1315 {
1316 handler->recvHeaders.httpError = 408;
|
1317 mike 1.1 handler->status = MI_RESULT_TIME_OUT;
|
1318 krisbash 1.3 }
1319 LOGE2((ZT("_RequestCallback - Timed out. socket: %d, result: %d (%s)"), handler->base.sock, handler->status, mistrerror(handler->status)));
|
1320 mike 1.1 return MI_FALSE;
1321 }
1322
|
1323 krisbash 1.3 if ((mask & SELECTOR_REMOVE) != 0 || (mask & SELECTOR_DESTROY) != 0)
|
1324 mike 1.1 {
1325 HttpClient* self = (HttpClient*)handler->base.data;
1326
1327 /* notify next stack layer */
|
1328 krisbash 1.3 if (handler->status != MI_RESULT_OK)
1329 (*self->callbackOnStatus)(self, self->callbackData, handler->status);
1330
1331 /* Yeah, this is hokey, but we need to sleep here to let the */
1332 /* subsystems have the opportunity to send the data before we close */
1333 /* the socket, or we'll get a broken pipe/connection reset */
1334 #if defined(CONFIG_OS_WINDOWS)
1335 Sleep_Milliseconds(1);
1336 #else
1337 usleep(50);
1338 #endif
1339
1340 if (handler == NULL)
1341 {
1342 LOGE2((ZT("_RequestCallback - The handler object was free'd under us!")));
1343 return MI_TRUE;
1344 }
|
1345 mike 1.1
|
1346 krisbash 1.3 self->connector = NULL;
|
1347 mike 1.1
1348 if (handler->ssl)
1349 SSL_free(handler->ssl);
1350
1351 Sock_Close(handler->base.sock);
1352
1353 if (handler->recvPage)
|
1354 krisbash 1.3 PAL_Free(handler->recvPage);
|
1355 mike 1.1
1356 if (handler->sendPage)
|
1357 krisbash 1.3 PAL_Free(handler->sendPage);
|
1358 mike 1.1
1359 if (handler->sendHeader)
|
1360 krisbash 1.3 PAL_Free(handler->sendHeader);
|
1361 mike 1.1
|
1362 krisbash 1.3 PAL_Free(handler->recvBuffer);
1363 PAL_Free(handler);
|
1364 mike 1.1 }
1365
1366 return MI_TRUE;
1367 }
1368
1369 #ifdef CONFIG_POSIX
|
1370 krisbash 1.3
1371 /*
1372 Verify callback when the server authentication certificate's chain of trust is checked. This
1373 is the same as the Open SSL verify callback function (return preverify_ok), except that it
1374 logs a diagnostic message when preverify_ok has a failed status.
1375 */
1376 static int _ctxVerify(
1377 int preverify_ok,
1378 X509_STORE_CTX* ctx)
|
1379 mike 1.1 {
|
1380 krisbash 1.3 if (preverify_ok <= 0)
1381 {
1382 X509* certWithError = X509_STORE_CTX_get_current_cert(ctx);
1383 int error = X509_STORE_CTX_get_error(ctx);
1384 char nameBuf[256];
|
1385 mike 1.1
|
1386 krisbash 1.3 X509_NAME_oneline(X509_get_subject_name(certWithError), nameBuf, 256);
1387 trace_SSL_VerifyFailed(error, nameBuf);
1388 }
1389 return preverify_ok;
1390 }
|
1391 mike 1.1
|
1392 krisbash 1.3 /*
1393 Create an Open SSL context that will be used for secure communication. Set up server and client
1394 certificate authentication if specified.
1395 */
1396 static MI_Result _CreateSSLContext(
1397 HttpClient* self,
1398 const char* trustedCertsDir,
1399 const char* certFile,
1400 const char* privateKeyFile)
1401 {
1402 SSL_CTX* sslContext = SSL_CTX_new(SSLv23_method());
1403 if (sslContext == NULL)
|
1404 mike 1.1 {
|
1405 krisbash 1.3 LOGE2((ZT("_CreateSSLContext - Cannot create SSL context")));
1406 trace_SSL_CannotCreateContext();
|
1407 mike 1.1 return MI_RESULT_FAILED;
1408 }
1409 SSL_CTX_set_quiet_shutdown(sslContext, 1);
|
1410 krisbash 1.3 (void)SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE);
|
1411 mike 1.1 SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
|
1412 krisbash 1.3 SSL_CTX_sess_set_remove_cb(sslContext, NULL);
1413
1414 if (trustedCertsDir != NULL)
|
1415 mike 1.1 {
|
1416 krisbash 1.3 /* Cause Open SSL to check the server certificate Subject against its FQDN and
1417 ** to check the server certificate chain against the contents of *trustedCertsDir.
1418 */
1419 if (SSL_CTX_load_verify_locations(sslContext, NULL, trustedCertsDir) < 0)
|
1420 mike 1.1 {
|
1421 krisbash 1.3 LOGE2((ZT("_CreateSSLContext - Cannot set directory containing trusted certificate(s) to %s"), trustedCertsDir));
1422 trace_SSL_BadTrustDir(trustedCertsDir);
|
1423 mike 1.1 }
|
1424 krisbash 1.3 SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER, _ctxVerify);
|
1425 mike 1.1 }
1426
|
1427 krisbash 1.3 /* Check if there is a client certificate file (file containing client authentication
1428 ** certificate) specified. If specified, validate and load the certificate.
|
1429 mike 1.1 */
|
1430 krisbash 1.3 if (certFile != NULL && *certFile != '\0')
|
1431 mike 1.1 {
|
1432 krisbash 1.3 int err;
1433
1434 /* load the specified client certificates */
1435 LOGD2((ZT("_CreateSSLContext - Loading server certificate from: %s"), certFile));
1436
1437 err = SSL_CTX_use_certificate_file(sslContext,
1438 certFile,
1439 strcmp(certFile + strlen(certFile) - 4, ".pem") == 0 ? SSL_FILETYPE_PEM : SSL_FILETYPE_ASN1);
1440 if (err <= 0)
1441 {
1442 #if defined(ENABLE_TRACING)
1443 unsigned long error = ERR_peek_last_error();
1444 #endif
1445
1446 LOGE2((ZT("_CreateSSLContext - No client certificate found in %s"), certFile));
1447 LOGE2((ZT("_CreateSSLContext - OpenSSL Error 0x%lX (%s) in SSL_CTX_use_certificate_file"), error, sslstrerror(error)));
|
1448 mike 1.1 SSL_CTX_free(sslContext);
|
1449 krisbash 1.3 sslContext = NULL;
|
1450 mike 1.1 return MI_RESULT_FAILED;
1451 }
|
1452 krisbash 1.3
1453 if (privateKeyFile != NULL && *privateKeyFile != '\0')
1454 {
1455 /* load the specified private key */
1456 LOGD2((ZT("_CreateSSLContext - SSL Loading client private key from: %s"), privateKeyFile));
1457
1458 err = SSL_CTX_use_RSAPrivateKey_file(sslContext,
1459 privateKeyFile,
1460 strcmp(privateKeyFile + strlen(privateKeyFile) - 4, ".pem") == 0 ? SSL_FILETYPE_PEM : SSL_FILETYPE_ASN1);
1461 if (err <= 0)
1462 {
1463 #if defined(ENABLE_TRACING)
1464 unsigned long error = ERR_peek_last_error();
1465 #endif
1466 LOGE2((ZT("_CreateSSLContext - Invalid private key found in %s"), privateKeyFile));
1467 LOGE2((ZT("_CreateSSLContext - OpenSSL error 0x%lX (%s) in SSL_CTX_use_PrivateKey_file"), error, sslstrerror(error)));
1468 SSL_CTX_free(sslContext);
1469 sslContext = NULL;
1470 return MI_RESULT_FAILED;
1471 }
1472 }
|
1473 mike 1.1 }
|
1474 krisbash 1.3
|
1475 mike 1.1 self->sslContext = sslContext;
1476 return MI_RESULT_OK;
1477 }
|
1478 krisbash 1.3
|
1479 mike 1.1 #endif
1480
|
1481 krisbash 1.3 static MI_Result _CreateSocketAndConnect(
1482 Sock* s,
1483 Addr* addr)
1484 {
1485 MI_Result r;
1486
1487 LOGD2((ZT("_CreateSocketAndConnect - Begin")));
1488
1489 /* Create client socket. */
1490 r = Sock_Create(s, addr->is_ipv6);
1491 if (r != MI_RESULT_OK)
1492 {
1493 LOGE2((ZT("_CreateSocketAndConnect - Sock_Create failed. result: %d (%s)"), r, mistrerror(r)));
1494 return r;
1495 }
1496
1497 /* set the socket to be non-blocking */
1498 r = Sock_SetBlocking(*s, MI_FALSE);
1499 if (r != MI_RESULT_OK)
1500 {
1501 LOGE2((ZT("_CreateSocketAndConnect - Sock_SetBlocking failed. result: %d (%s)"), r, mistrerror(r)));
1502 krisbash 1.3 return r;
1503 }
1504
1505 /* connect the socket to the IP address */
1506 r = Sock_Connect(*s, addr);
1507 if (r != MI_RESULT_OK)
1508 {
1509 LOGE2((ZT("_CreateSocketAndConnect - Sock_Connect failed. result: %d (%s)"), r, mistrerror(r)));
1510 return r;
1511 }
1512
1513 LOGD2((ZT("_CreateSocketAndConnect - OK exit")));
1514
1515 return MI_RESULT_WOULD_BLOCK;
1516 }
1517
|
1518 mike 1.1 static MI_Result _CreateConnectorSocket(
1519 HttpClient* self,
1520 const char* host,
1521 unsigned short port,
1522 MI_Boolean secure)
1523 {
1524 Addr addr;
1525 MI_Result r;
1526 Sock s;
|
1527 krisbash 1.3 HttpClient_SR_SocketData* h;
|
1528 mike 1.1 MI_Uint64 currentTimeUsec;
1529
|
1530 krisbash 1.3 LOGD2((ZT("_CreateConnectorSocket - Begin. host: %s, port: %d, secure? %d"), host, port, secure));
1531
|
1532 mike 1.1 /* timeout calculation */
|
1533 krisbash 1.3 if (PAL_Time(¤tTimeUsec) != PAL_TRUE)
|
1534 mike 1.1 {
|
1535 krisbash 1.3 LOGE2((ZT("_CreateConnectorSocket - PAL_Time failed")));
|
1536 mike 1.1 return MI_RESULT_FAILED;
1537 }
1538
|
1539 krisbash 1.3 /* This code tries to connect using the preferred addressing family (IPv4 */
1540 /* or IPv6). If that fails and Addr_Init has a secondary addressing */
1541 /* family, a connection with the secondary family, it tries using the */
1542 /* secondary family next. */
1543
1544 /* Initialize preferred address */
1545 r = Addr_Init(&addr, host, port, MI_FALSE);
|
1546 mike 1.1 if (r != MI_RESULT_OK)
1547 {
|
1548 krisbash 1.3 LOGE2((ZT("_CreateConnectorSocket - Addr_Init failed. result: %d (%s)"), r, mistrerror(r)));
1549 return r;
|
1550 mike 1.1 }
1551
|
1552 krisbash 1.3 /* Connect to the server */
1553 r = _CreateSocketAndConnect(&s, &addr);
|
1554 mike 1.1 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1555 {
|
1556 krisbash 1.3 MI_Result r2;
1557
|
1558 mike 1.1 Sock_Close(s);
|
1559 krisbash 1.3
1560 LOGW2((ZT("_CreateConnectorSocket - _CreateSocketAndConnect of primary address failed. result: %d (%s)"), r, mistrerror(r)));
1561
1562 /* Initialize secondary address */
1563 r2 = Addr_Init(&addr, host, port, MI_TRUE);
1564 if (r2 != MI_RESULT_OK)
1565 return r; /* on error, return original failure */
1566 r2 = _CreateSocketAndConnect(&s, &addr);
1567 if (r2 != MI_RESULT_OK && r2 != MI_RESULT_WOULD_BLOCK)
1568 {
1569 Sock_Close(s);
1570
1571 LOGE2((ZT("_CreateConnectorSocket - Addr_Init failed. result: %d (%s)"), r, mistrerror(r)));
|
1572 krisbash 1.4
|
1573 krisbash 1.3 return r; /* on error, return original failure */
1574 }
1575 r = r2;
|
1576 mike 1.1 }
1577
1578 /* Create handler */
|
1579 krisbash 1.3 h = (HttpClient_SR_SocketData*)PAL_Calloc(1, sizeof(HttpClient_SR_SocketData));
|
1580 mike 1.1
|
1581 krisbash 1.3 if (h == NULL)
|
1582 mike 1.1 {
1583 Sock_Close(s);
|
1584 krisbash 1.3 LOGE2((ZT("_CreateConnectorSocket - calloc failed")));
|
1585 mike 1.1 return MI_RESULT_FAILED;
1586 }
1587
1588 h->recvBufferSize = INITIAL_BUFFER_SIZE;
|
1589 krisbash 1.3 h->recvBuffer = (char*)PAL_Calloc(1, h->recvBufferSize);
|
1590 mike 1.1 if (!h->recvBuffer)
1591 {
|
1592 krisbash 1.3 PAL_Free(h);
|
1593 mike 1.1 Sock_Close(s);
|
1594 krisbash 1.3 LOGE2((ZT("_CreateConnectorSocket - calloc failed")));
|
1595 mike 1.1 return MI_RESULT_FAILED;
1596 }
1597
1598 h->base.sock = s;
1599 h->base.mask = SELECTOR_EXCEPTION;
1600 h->base.callback = _RequestCallback;
1601 h->base.data = self;
1602 h->timeoutUsec = DEFAULT_HTTP_TIMEOUT_USEC;
1603 h->base.fireTimeoutAt = currentTimeUsec + h->timeoutUsec;
1604
|
1605 krisbash 1.3 /* SSL support */
|
1606 mike 1.1 if (secure)
1607 {
1608 h->ssl = SSL_new(self->sslContext);
1609
1610 if (!h->ssl)
1611 {
|
1612 krisbash 1.3 LOGW2((ZT("_CreateConnectorSocket - SSL_new failed")));
1613 trace_SSLNew_Failed();
1614 PAL_Free(h);
|
1615 mike 1.1 Sock_Close(s);
1616 return MI_RESULT_FAILED;
1617 }
1618
|
1619 krisbash 1.3 Sock_SetBlocking(s, MI_TRUE);
|
1620 mike 1.1 if (!(SSL_set_fd(h->ssl, s) ))
1621 {
|
1622 krisbash 1.3 LOGW2((ZT("_CreateConnectorSocket - SSL_set_fd failed")));
1623 trace_SSL_setfd_Failed();
|
1624 mike 1.1 SSL_free(h->ssl);
|
1625 krisbash 1.3 PAL_Free(h);
|
1626 mike 1.1 Sock_Close(s);
1627 return MI_RESULT_FAILED;
1628 }
1629
1630 SSL_set_connect_state(h->ssl);
1631 }
1632
1633 /* Watch for read events on the incoming connection */
1634 r = Selector_AddHandler(self->selector, &h->base);
1635
1636 if (r != MI_RESULT_OK)
1637 {
|
1638 krisbash 1.3 LOGE2((ZT("_CreateConnectorSocket - Selector_AddHandler failed with error: %d (%s)"), (int)r, mistrerror(r)));
1639 trace_SelectorAddHandler_Failed();
|
1640 mike 1.1 if (secure)
1641 SSL_free(h->ssl);
|
1642 krisbash 1.3 PAL_Free(h);
|
1643 mike 1.1 Sock_Close(s);
1644 return MI_RESULT_FAILED;
1645 }
1646
1647 self->connector = h;
1648
|
1649 krisbash 1.3 LOGD2((ZT("_CreateConnectorSocket - OK exit. socket: %d, secure: %d, timeout: %s"), h->base.sock, secure, FmtInterval(h->base.fireTimeoutAt - currentTimeUsec)));
1650
|
1651 mike 1.1 return MI_RESULT_OK;
1652 }
1653
1654 static MI_Result _New_Http(
1655 HttpClient** selfOut,
1656 Selector* selector, /*optional, maybe NULL*/
1657 HttpClientCallbackOnStatus statusCallback,
1658 HttpClientCallbackOnResponse responseCallback,
1659 void* callbackData)
1660 {
1661 HttpClient* self;
1662
1663 /* Check parameters */
1664 if (!selfOut)
1665 return MI_RESULT_INVALID_PARAMETER;
1666
1667 /* Clear output parameter */
1668 *selfOut = NULL;
1669
1670 /* Allocate structure */
1671 {
|
1672 krisbash 1.3 self = (HttpClient*)PAL_Calloc(1, sizeof(HttpClient));
|
1673 mike 1.1
1674 if (!self)
1675 return MI_RESULT_FAILED;
1676 }
1677
1678 if (selector)
1679 { /* attach the exisiting selector */
1680 self->selector = selector;
1681 self->internalSelectorUsed = MI_FALSE;
1682 }
1683 else
1684 { /* creaet a new selector */
1685 /* Initialize the network */
1686 Sock_Start();
1687
1688 /* Initialize the selector */
1689 if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)
1690 {
|
1691 krisbash 1.3 PAL_Free(self);
1692 LOGE2((ZT("_NewHttp - Selector_Init failed")));
|
1693 mike 1.1 return MI_RESULT_FAILED;
1694 }
1695 self->selector = &self->internalSelector;
1696 self->internalSelectorUsed = MI_TRUE;
1697 }
1698
1699 /* Save the callback and callbackData */
1700 self->callbackOnResponse = responseCallback;
1701 self->callbackOnStatus = statusCallback;
1702 self->callbackData = callbackData;
1703
1704 /* Set the magic number */
1705 self->magic = _MAGIC;
1706
1707 /* Set output parameter */
1708 *selfOut = self;
1709 return MI_RESULT_OK;
1710 }
1711
1712
1713
1714 mike 1.1 static size_t _GetHeadersSize(
1715 const HttpClientRequestHeaders* headers)
1716 {
1717 size_t res = 0;
1718 size_t index = 0;
1719
1720 while (index < headers->size)
1721 {
1722 res += Strlen(headers->data[index]);
1723 res += 2; /* \r \n pair */
1724 index++;
1725 }
1726
1727 return res;
1728 }
1729
1730 static Page* _CreateHttpHeader(
1731 const char* verb,
1732 const char* uri,
1733 const HttpClientRequestHeaders* headers,
1734 size_t size)
1735 mike 1.1 {
1736 Page* page = 0;
1737 size_t pageSize = 0;
1738 int r;
1739 char* p;
1740
1741 #define HTTP_HEADER_FORMAT "%s %s HTTP/1.1\r\n" \
1742 "Content-Length: %d\r\n"\
1743 "Connection: Keep-Alive\r\n" \
1744 "Host: host\r\n"
1745
1746 #define HTTP_HEADER_FORMAT_NOCL "%s %s HTTP/1.1\r\n" \
1747 "Connection: Keep-Alive\r\n" \
1748 "Host: host\r\n"
1749
1750 /* calculate approximate page size */
1751 if (!verb)
1752 verb = "POST";
|
1753 krisbash 1.4
|
1754 mike 1.1 pageSize += sizeof(HTTP_HEADER_FORMAT) + 10; /* format + 10 digits of content length */
1755
|
1756 krisbash 1.4 if (SizeTAdd(pageSize, Strlen(verb), &pageSize) != S_OK ||
1757 SizeTAdd(pageSize, Strlen(uri), &pageSize) != S_OK ||
1758 SizeTAdd(pageSize, sizeof(Page), &pageSize) != S_OK ||
1759 (headers && SizeTAdd(pageSize, _GetHeadersSize(headers), &pageSize)) != S_OK)
1760 {
1761 // Overflow
1762 return 0;
1763 }
|
1764 mike 1.1
|
1765 krisbash 1.4 page = (Page*)PAL_Malloc(pageSize);
|
1766 mike 1.1
1767 if (!page)
1768 return 0;
1769
1770 /* clear header */
1771 memset(page, 0, sizeof(Page));
1772
1773 p = (char*)(page + 1);
1774
1775 if (size)
1776 r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT, verb, uri, (int)size);
1777 else
1778 r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT_NOCL, verb, uri);
1779
1780 if (r < 0)
1781 {
|
1782 krisbash 1.3 PAL_Free(page);
|
1783 mike 1.1 return 0;
1784 }
1785
1786 p += r;
1787 pageSize -= r;
1788
1789 if (headers)
1790 {
1791 size_t index = 0;
1792
1793 while (index < headers->size)
1794 {
1795 r = (int)Strlcpy(p,headers->data[index], pageSize);
1796 p += r;
1797 pageSize -= r;
1798 r = (int)Strlcpy(p,"\r\n", pageSize);
1799 p += r;
1800 pageSize -= r;
1801
1802 index++;
1803 }
1804 mike 1.1 }
1805
1806 /* add trailing \r\n */
1807 r = (int)Strlcpy(p,"\r\n", pageSize);
1808 p += r;
1809 pageSize -= r;
1810
1811 page->u.s.size = (unsigned int)(p - (char*)(page+1));
1812
1813 return page;
1814 }
1815
1816 /* ************************************************************************* *\
1817 HTTP CLIENT
1818 \* ************************************************************************* */
1819 /*
1820 Creates new http client.
1821
1822 Parameters:
1823 selfOut - [out] newly created http object (or null if failed).
1824 selector - [opt] selector to use for socket monitoring. If selector not specified,
1825 mike 1.1 private one is created.
1826 host - host address
1827 port - port number
1828 secure - flag that indicates if http or https conneciton is required
1829
1830 Returns:
1831 'OK' on success or error code otherwise
1832 */
1833 MI_Result HttpClient_New_Connector(
1834 HttpClient** selfOut,
1835 Selector* selector, /*optional, maybe NULL*/
1836 const char* host,
1837 unsigned short port,
1838 MI_Boolean secure,
1839 HttpClientCallbackOnStatus statusCallback,
1840 HttpClientCallbackOnResponse responseCallback,
|
1841 krisbash 1.3 void* callbackData,
1842 const char* trustedCertsDir,
1843 const char* certFile,
1844 const char* privateKeyFile)
|
1845 mike 1.1 {
1846 HttpClient* self;
1847 MI_Result r;
1848
1849 /* allocate this, inits selector */
|
1850 krisbash 1.3 r = _New_Http(selfOut, selector, statusCallback,
1851 responseCallback, callbackData);
|
1852 mike 1.1
1853 if (MI_RESULT_OK != r)
|
1854 krisbash 1.3 {
1855 LOGE2((ZT("HttpClient_New_Connector - _New_Http failed. result: %d (%s)"), r, mistrerror(r)));
|
1856 mike 1.1 return r;
|
1857 krisbash 1.3 }
|
1858 mike 1.1 self = *selfOut;
1859
1860 #ifdef CONFIG_POSIX
|
1861 krisbash 1.3 /* Allocate SSL context */
|
1862 mike 1.1 if (secure)
1863 {
1864 /* init ssl */
1865 SSL_library_init();
1866
1867 /* create context */
|
1868 krisbash 1.3 r = _CreateSSLContext(self, trustedCertsDir, certFile, privateKeyFile);
|
1869 mike 1.1
1870 if (r != MI_RESULT_OK)
1871 {
1872 HttpClient_Delete(self);
|
1873 krisbash 1.3 *selfOut = NULL;
1874 LOGE2((ZT("HttpClient_New_Connector - _CreateSSLContext failed. result: %d (%s)"), r, mistrerror(r)));
|
1875 mike 1.1 return r;
1876 }
1877 }
1878 #else
1879 MI_UNUSED(secure);
1880 #endif
1881
1882 /* Create http connector socket */
1883 {
1884 r = _CreateConnectorSocket(self, host, port, secure);
1885
1886 if (r != MI_RESULT_OK)
1887 {
1888 HttpClient_Delete(self);
|
1889 krisbash 1.3 LOGE2((ZT("HttpClient_New_Connector - _CreateConnectorSocket failed failed. result: %d (%s)"), r, mistrerror(r)));
|
1890 mike 1.1 return r;
1891 }
1892 }
1893
1894 return MI_RESULT_OK;
1895 }
1896
1897 /*
1898 Deletes http object, disconnects form the server
1899 and frees all related resources.
|
1900 krisbash 1.3
|
1901 mike 1.1 Parameters:
1902 self - http object
1903
1904 Returns:
1905 OK
1906 */
1907 MI_Result HttpClient_Delete(
1908 HttpClient* self)
1909 {
1910 /* Check parameters */
1911 if (!self)
1912 return MI_RESULT_INVALID_PARAMETER;
1913
1914 /* Check magic number */
1915 if (self->magic != _MAGIC)
|
1916 krisbash 1.3 {
1917 LOGE2((ZT("HttpClient_Delete - Bad magic number")));
|
1918 mike 1.1 return MI_RESULT_INVALID_PARAMETER;
|
1919 krisbash 1.3 }
|
1920 mike 1.1
1921 if (self->internalSelectorUsed)
1922 {
1923 /* Release selector;
|
1924 krisbash 1.3 Note: Selector_Destroy closes all sockets in a list including connector and listener */
|
1925 mike 1.1 Selector_Destroy(self->selector);
1926
1927 /* Shutdown the network */
1928 Sock_Stop();
1929 }
1930 else
1931 {
1932 /* remove connector from handler */
1933 if (self->connector)
1934 Selector_RemoveHandler(self->selector, &self->connector->base);
1935 }
1936
1937 if (self->sslContext)
1938 SSL_CTX_free(self->sslContext);
1939
1940 /* Clear magic number */
1941 self->magic = 0xDDDDDDDD;
1942
1943 /* Free self pointer */
|
1944 krisbash 1.3 PAL_Free(self);
|
1945 mike 1.1
1946 return MI_RESULT_OK;
1947 }
1948
1949
|
1950 krisbash 1.3 /*
|
1951 mike 1.1 Sends http request.
1952
1953 Parameters:
1954 self - http object
1955 uri - request's URI
|
1956 krisbash 1.3 headers - [opt] extra headers for request.
1957 data - [opt] content to send. if message is accepted to be sent,
|
1958 mike 1.1 on return *data == null (taking memory ownership)
1959
1960 Returns:
1961 OK or appropriate error
1962 */
1963 MI_Result HttpClient_StartRequest(
1964 HttpClient* self,
1965 const char* verb,
1966 const char* uri,
1967 const HttpClientRequestHeaders* headers,
1968 Page** data)
1969 {
|
1970 krisbash 1.3 LOGD2((ZT("HttpClient_StartRequest - Begin. verb: %s, URI: %s"), verb, uri));
|
1971 mike 1.1
1972 /* check params */
1973 if (!self || !uri)
1974 return MI_RESULT_INVALID_PARAMETER;
1975
1976 if (self->magic != _MAGIC)
1977 {
|
1978 krisbash 1.3 LOGE2((ZT("HttpClient_Delete - Bad magic number")));
1979 trace_StartRequest_InvalidMagic();
|
1980 mike 1.1 return MI_RESULT_INVALID_PARAMETER;
1981 }
1982
|
1983 krisbash 1.3 if (self->connector == NULL)
|
1984 mike 1.1 {
|
1985 krisbash 1.3 LOGE2((ZT("HttpClient_Delete - Connection is not open")));
1986 trace_StartRequest_ConnectionClosed();
|
1987 mike 1.1 return MI_RESULT_FAILED;
1988 }
1989
1990 /* create header page */
1991 self->connector->sendHeader =
1992 _CreateHttpHeader(verb, uri, headers, (data && *data) ? (*data)->u.s.size : 0);
|
1993 krisbash 1.3
1994 if (data != NULL)
|
1995 mike 1.1 {
1996 self->connector->sendPage = *data;
1997 *data = 0;
1998 }
1999 else
|
2000 krisbash 1.3 self->connector->sendPage = NULL;
|
2001 mike 1.1
2002 /* set status to failed, until we know more details */
2003 self->connector->status = MI_RESULT_FAILED;
2004 self->connector->sentSize = 0;
2005 self->connector->sendingState = RECV_STATE_HEADER;
2006 self->connector->base.mask |= SELECTOR_WRITE;
2007
2008 _RequestCallbackWrite(self->connector);
2009
2010 return MI_RESULT_OK;
2011 }
2012
2013 MI_Result HttpClient_Run(
2014 HttpClient* self,
2015 MI_Uint64 timeoutUsec)
2016 {
2017 /* Run the selector */
|
2018 krisbash 1.3 return Selector_Run(self->selector, timeoutUsec, MI_FALSE);
|
2019 mike 1.1 }
2020
2021 MI_Result HttpClient_SetTimeout(
2022 HttpClient* self,
2023 MI_Uint64 timeoutUsec)
2024 {
2025 MI_Uint64 currentTimeUsec = 0;
2026
|
2027 krisbash 1.3 PAL_Time(¤tTimeUsec);
|
2028 mike 1.1
2029 /* check params */
2030 if (!self)
2031 return MI_RESULT_INVALID_PARAMETER;
2032
2033 if (self->magic != _MAGIC)
2034 {
|
2035 krisbash 1.3 trace_Timeout_InvalidMagic();
|
2036 mike 1.1 return MI_RESULT_INVALID_PARAMETER;
2037 }
2038
2039 if (!self->connector)
2040 return MI_RESULT_INVALID_PARAMETER;
2041
2042 /* create header page */
2043 self->connector->timeoutUsec = timeoutUsec;
2044 self->connector->base.fireTimeoutAt = currentTimeUsec + self->connector->timeoutUsec;
2045
2046 return MI_RESULT_OK;
2047 }
|