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