1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** 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 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** 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 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include <assert.h>
26 #include <ctype.h>
27 //#include "http.h"
28 #include "httpclient.h"
29 #include "addr.h"
30 #include "sock.h"
31 #include "selector.h"
32 #include <base/time.h>
33 #include <base/buf.h>
34 #include <base/log.h>
35 #include <base/result.h>
36 #include <base/strings.h>
37 #include <base/io.h>
38 #include <base/paths.h>
39
40 #ifdef CONFIG_POSIX
41 #include <openssl/ssl.h>
42 #include <openssl/err.h>
43 mike 1.1 #else
44 /* ssl not supported in this configuration; just make compiler happy */
45 typedef void SSL;
46 typedef void SSL_CTX;
47 #define SSL_CTX_free(c)
48 #define SSL_new(c) 0
49 #define SSL_free(c)
50 #define SSL_set_connect_state(c)
51 #define SSL_set_fd(c,a) (a==a)
52 #define SSL_read(c,a,b) 0
53 #define SSL_write(c,a,b) 0
54 #define SSL_get_error(c,e) e
55 #define SSL_ERROR_WANT_WRITE 0
56 #define SSL_ERROR_WANT_READ 1
57 #define SSL_ERROR_SYSCALL 2
58
59 #ifdef EWOULDBLOCK
60 # undef EWOULDBLOCK
61 #endif
62
63 #define EWOULDBLOCK 0
64 mike 1.1
65 #ifdef EINPROGRESS
66 # undef EINPROGRESS
67 #endif
68
69 #define EINPROGRESS 0
70
71 #define ERR_get_error() 0
72 #define ERR_error_string_n(c,a,b) a[0]=0
73 #define SSL_accept(c) 0
74 #define SSL_connect(c) 0
75
76 #endif
77
78 #define T MI_T
79
80 /* #define ENABLE_TRACING // */
81 #ifdef ENABLE_TRACING
82 #define PRINTF(a) TIMESTAMP(); printf a
83 #define TIMESTAMP() \
84 {\
85 mike 1.1 MI_Uint64 currentTimeUsec = 0;\
86 \
87 Time_Now(¤tTimeUsec);\
88 currentTimeUsec /= 1000; /* ms */ \
89 printf("%ds%03dms ", (int)(currentTimeUsec / 1000 % 1000), (int)(currentTimeUsec % 1000));\
90 }
91
92 #define PRINTF_2(a)
93 #else
94 #define PRINTF(a)
95 #define PRINTF_2(a)
96 #endif
97
98
99
100 /*
101 **==============================================================================
102 **
103 ** Local definitions:
104 **
105 **==============================================================================
106 mike 1.1 */
107
108 static const MI_Uint32 _MAGIC = 0x5FC7B966;
109 static const MI_Uint32 MAX_HEADER_SIZE = 2 * 1024;
110 static const MI_Uint32 INITIAL_BUFFER_SIZE = 2 * 1024;
111 static const MI_Uint32 DEFAULT_HTTP_TIMEOUT_USEC = 60 * 1000000;
112
113 typedef enum _Http_RecvState
114 {
115 RECV_STATE_HEADER,
116 RECV_STATE_CONTENT,
117 RECV_STATE_CHUNKHEADER,
118 RECV_STATE_CHUNKDATA
119 }
120 Http_RecvState;
121
122 typedef struct _Http_SR_SocketData
123 {
124 /* based member*/
125 Handler base;
126
127 mike 1.1 /* timeout */
128 MI_Uint64 timeoutUsec;
129
130 /* ssl part */
131 SSL* ssl;
132 MI_Boolean reverseOperations; /*reverse read/write Events/Handlers*/
133 MI_Boolean connectDone;
134
135 /* receiving data */
136 char* recvBuffer;
137 size_t recvBufferSize;
138 size_t recvievedSize;
139 Http_RecvState recvingState;
140 HttpClientHeaderField recvHeaderFields[64];
141 HttpClientResponseHeader recvHeaders;
142 MI_Sint64 contentLength;
143 Page* recvPage;
144
145 /* sending part */
146 Page* sendPage;
147 Page* sendHeader;
148 mike 1.1 size_t sentSize;
149 Http_RecvState sendingState;
150
151 /* general operation status */
152 MI_Result status;
153
154 }
155 Http_SR_SocketData;
156
157 struct _HttpClient
158 {
159 MI_Uint32 magic;
160 Selector internalSelector;
161 Selector* selector;
162 HttpClientCallbackOnStatus callbackOnStatus;
163 HttpClientCallbackOnResponse callbackOnResponse;
164 void* callbackData;
165 SSL_CTX* sslContext;
166
167 Http_SR_SocketData* connector;
168
169 mike 1.1 MI_Boolean internalSelectorUsed;
170 };
171
172
173 /* helper functions result */
174 typedef enum _Http_CallbackResult
175 {
176 PRT_CONTINUE,
177 PRT_RETURN_TRUE,
178 PRT_RETURN_FALSE
179 }
180 Http_CallbackResult;
181
182
183 MI_INLINE MI_Uint8 _ToLower(MI_Uint8 x)
184 {
185 return (MI_Uint8)tolower(x);
186 }
187
188 #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8) | (((MI_Uint16)len)) )
189
190 mike 1.1 static MI_Boolean _getNameValuePair(
191 char ** line,
192 char ** value,
193 int* nameHashCode )
194 {
195 int len = 0;
196 char* p;
197 /* find name end /hash-code */
198
199 *nameHashCode = _ToLower((MI_Uint8)(*line)[0])<<16;
200
201 for (len = 1; (*line)[len] != ':' && (*line)[len] != '\r'; len++ )
202 ;
203
204 if ((*line)[len] != ':')
205 return MI_FALSE;
206
207 *nameHashCode |= (len) | _ToLower((MI_Uint8)(*line)[len-1])<<8;
208 (*line)[len] = 0;
209 p = *line + len + 1;
210
211 mike 1.1 /* skip spaces in value */
212 while (p[0] == ' ' || p[0] == '\t')
213 p++;
214
215 *value = p;
216
217 /* skip to end of line */
218 for ( ; ; )
219 {
220 if (p[0] == '\r' && p[1] == '\n' &&
221 (p[2] != ' ' && p[2] != '\t') )
222 {
223 p[0] = 0;
224 (*line) = p + 2;
225 break;
226 }
227 p ++;
228 }
229
230 /* remove trailing spaces */
231 p--;
232 mike 1.1 while (p[0] == ' ' || p[0] == '\t')
233 p--;
234
235 p[1] = 0;
236
237 return MI_TRUE;
238 }
239
240
241 static MI_Boolean _getHeaderField(
242 Http_SR_SocketData* handler,
243 char ** line)
244 {
245 /* expecting Request-Line = Method SP Request-URI SP HTTP-Version CRLF
246 Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
247 */
248 char* name = *line;
249 char* value = NULL;
250 int nameHashCode;
251
252 if (!_getNameValuePair(line, &value, &nameHashCode))
253 mike 1.1 return MI_FALSE;
254
255
256 if (nameHashCode == _HashCode('c','h',14) && /*Content-Length*/
257 Strcasecmp(name,"Content-Length") == 0)
258 {
259 handler->contentLength = Strtoull(value, NULL, 10);
260 /*if ( handler->contentLength > HTTP_MAX_CONTENT )
261 return MI_FALSE;*/
262 }
263 else if (nameHashCode == _HashCode('t','g',17) && /*Transfer-Encoding*/
264 Strcasecmp(name,"Transfer-Encoding") == 0)
265 {
266 handler->contentLength = -1;
267 }
268
269 else
270 {
271 if (handler->recvHeaders.sizeHeaders < MI_COUNT(handler->recvHeaderFields))
272 {
273 handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].name = name;
274 mike 1.1 handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].value = value;
275 handler->recvHeaders.sizeHeaders++;
276 }
277 else
278 {
279 LOGW_CHAR(("too many http headers; skipping %s: %s\n", name, value));
280 }
281 }
282
283 return MI_TRUE;
284 }
285
286 static MI_Boolean _getChunkSize(
287 const char * line,
288 MI_Uint32* chunkSize)
289 {
290 *chunkSize = 0;
291
292 while(*line)
293 {
294 char c = *line;
295 mike 1.1
296 if (c >= '0' && c <= '9')
297 *chunkSize = *chunkSize * 16 + (c - '0');
298 else if (c >= 'a' && c <= 'f')
299 *chunkSize = *chunkSize * 16 + (c - 'a' + 10);
300 else if (c >= 'A' && c <= 'F')
301 *chunkSize = *chunkSize * 16 + (c - 'A' + 10);
302 else
303 break;
304
305 line++;
306 }
307
308 return MI_TRUE;
309 }
310
311
312 static MI_Boolean _getRequestLine(
313 Http_SR_SocketData* handler,
314 char ** line)
315 {
316 mike 1.1 size_t index;
317 /* expecting Request-Line = Method SP Request-URI SP HTTP-Version CRLF
318 Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
319 */
320
321 /* initialize header */
322 handler->recvHeaders.sizeHeaders = 0;
323 handler->recvHeaders.headers = handler->recvHeaderFields;
324
325 /* find http code */
326 {
327 /* skip http version, that is in format
328 HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
329 http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.1
330
331 Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
332 */
333 const char* s = *line + 9; /*+ HTTP/1.1<sp>*/
334
335 handler->recvHeaders.httpError = Strtoul(s, NULL, 10);
336 }
337 mike 1.1
338 /* skip to end of line */
339 for ( index = 1; index < handler->recvievedSize; index++ )
340 {
341 if ((*line)[index-1] == '\r' && (*line)[index] == '\n' )
342 {
343 (*line) = (*line) + index + 1;
344 return MI_TRUE;
345 }
346 }
347
348 return MI_FALSE;
349 }
350
351 static MI_Result _Sock_Read(
352 Http_SR_SocketData* handler,
353 void* buf,
354 size_t buf_size,
355 size_t* sizeRead)
356 {
357 int res;
358 mike 1.1
359 if (!handler->ssl)
360 return Sock_Read(handler->base.sock, buf, buf_size, sizeRead);
361
362 handler->base.mask &= ~SELECTOR_WRITE;
363 handler->base.mask |= SELECTOR_READ;
364 handler->reverseOperations = MI_FALSE;
365
366 *sizeRead = 0;
367
368 res = SSL_read(handler->ssl, buf, buf_size);
369 PRINTF(("ssl read %d\n", res));
370
371 if ( res == 0 )
372 return MI_RESULT_OK; /* connection closed */
373
374 if ( res > 0 )
375 {
376 *sizeRead = res;
377 return MI_RESULT_OK; /* ok */
378 }
379 mike 1.1
380 switch (SSL_get_error(handler->ssl, res))
381 {
382 case SSL_ERROR_WANT_WRITE:
383 handler->reverseOperations = MI_TRUE; /* wait until write is allowed */
384 handler->base.mask &= ~SELECTOR_READ;
385 handler->base.mask |= SELECTOR_WRITE;
386 PRINTF(("ssl read/accept WANT_WRITE\n"));
387 return MI_RESULT_WOULD_BLOCK;
388
389 case SSL_ERROR_WANT_READ:
390 PRINTF(("ssl read/accept WANT_READ\n"));
391 return MI_RESULT_WOULD_BLOCK;
392
393 case SSL_ERROR_SYSCALL:
394 if (EAGAIN == errno ||
395 EWOULDBLOCK == errno ||
396 EINPROGRESS == errno)
397 return MI_RESULT_WOULD_BLOCK;
398
399 LOGW_CHAR(("ssl-read: unexpected sys error %d\n", errno));
400 mike 1.1 break;
401
402 default:
403 {
404 /* print error */
405 unsigned long err = ERR_get_error();
406 while (err)
407 {
408 char err_txt[200];
409 ERR_error_string_n(err, err_txt, sizeof(err_txt));
410
411 LOGW_CHAR(("ssl-read error: %d [%s]\n", (int)err, err_txt));
412
413 err = ERR_get_error();
414 }
415 }
416 break;
417 }
418 return MI_RESULT_FAILED;
419 }
420
421 mike 1.1 static MI_Result _Sock_Write(
422 Http_SR_SocketData* handler,
423 void* buf,
424 size_t buf_size,
425 size_t* sizeWritten)
426 {
427 int res;
428
429 if (!handler->ssl)
430 return Sock_Write(handler->base.sock, buf, buf_size, sizeWritten);
431
432 /* Do not clear READ flag, since 'close' notification
433 delivered as READ event */
434 handler->base.mask &= ~SELECTOR_READ;
435 handler->base.mask |= SELECTOR_WRITE;
436 handler->reverseOperations = MI_FALSE;
437
438 *sizeWritten = 0;
439
440 if (handler->connectDone)
441 {
442 mike 1.1 res = SSL_write(handler->ssl, buf, buf_size);
443 PRINTF(("ssl write %d\n", res));
444 }
445 else
446 {
447 res = SSL_connect(handler->ssl);
448 PRINTF(("ssl connect %d\n", res));
449 if ( res > 0 )
450 {
451 /* we are done with accpet */
452 handler->connectDone = MI_TRUE;
453 return _Sock_Write(handler,buf,buf_size,sizeWritten);
454 }
455 /* perform regular error checking */
456 }
457
458
459 if ( res == 0 )
460 return MI_RESULT_OK; /* connection closed */
461
462 if ( res > 0 )
463 mike 1.1 {
464 *sizeWritten = res;
465 return MI_RESULT_OK; /* ok */
466 }
467
468 switch (SSL_get_error(handler->ssl, res))
469 {
470 case SSL_ERROR_WANT_WRITE:
471 PRINTF(("ssl write/connetc WANT_WRITE\n"));
472 return MI_RESULT_WOULD_BLOCK;
473
474 case SSL_ERROR_WANT_READ:
475 PRINTF(("ssl write/connetc WANT_READ\n"));
476 handler->reverseOperations = MI_TRUE; /* wait until write is allowed */
477 handler->base.mask |= SELECTOR_READ;
478 handler->base.mask &= ~SELECTOR_WRITE;
479 return MI_RESULT_WOULD_BLOCK;
480
481 case SSL_ERROR_SYSCALL:
482 if (EAGAIN == errno ||
483 EWOULDBLOCK == errno ||
484 mike 1.1 EINPROGRESS == errno)
485 return MI_RESULT_WOULD_BLOCK;
486
487 LOGW_CHAR(("ssl-write: unexpected sys error %d\n", errno));
488 break;
489
490 default:
491 break;
492 }
493 return MI_RESULT_FAILED;
494 }
495
496 static Http_CallbackResult _ReadHeader(
497 Http_SR_SocketData* handler)
498 {
499 char* buf;
500 char* currentLine;
501 char* data;
502 size_t buf_size, received, index;
503 MI_Result r;
504 MI_Boolean fullHeaderReceived = MI_FALSE;
505 mike 1.1
506 /* are we done with header? */
507 if (handler->recvingState != RECV_STATE_HEADER)
508 return PRT_CONTINUE;
509
510 buf = handler->recvBuffer + handler->recvievedSize;
511 buf_size = handler->recvBufferSize - handler->recvievedSize;
512 received = 0;
513
514 r = _Sock_Read(handler, buf, buf_size, &received);
515 PRINTF(("%d: read r = %d, recv = %d; reverse %d\n", (int)handler->base.sock, (int)r, (int)received, (int)handler->reverseOperations ));
516
517 if ( r == MI_RESULT_OK && 0 == received )
518 return PRT_RETURN_FALSE; /* conection closed */
519
520 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
521 return PRT_RETURN_FALSE;
522
523 if (!received)
524 return PRT_RETURN_TRUE;
525
526 mike 1.1 handler->recvievedSize += received;
527
528 /* check header */
529 PRINTF_2(("%s\n",buf));
530
531 /* did we get full header? */
532 buf = handler->recvBuffer;
533 for ( index = 3; index < handler->recvievedSize; index++ )
534 {
535 if (buf[index-3] == '\r' && buf[index-1] == '\r' &&
536 buf[index-2] == '\n' && buf[index] == '\n' )
537 {
538 fullHeaderReceived = MI_TRUE;
539 break;
540 }
541 }
542
543 if (!fullHeaderReceived )
544 {
545 if ( handler->recvievedSize < handler->recvBufferSize )
546 return PRT_RETURN_TRUE; /* continue reading */
547 mike 1.1
548 if ( handler->recvBufferSize < MAX_HEADER_SIZE )
549 {
550 buf = realloc(handler->recvBuffer, handler->recvBufferSize * 2);
551
552 if (!buf)
553 return PRT_RETURN_FALSE;
554
555 handler->recvBufferSize *= 2;
556 handler->recvBuffer = buf;
557 return _ReadHeader(handler);
558 }
559 else
560 {
561 /* http header is too big - drop connection */
562 LOGW((T("http header is too big; dropping connection\n")));
563 return PRT_RETURN_FALSE;
564 }
565 }
566
567 /* consume data */
568 mike 1.1 currentLine = buf;
569 data = buf + index + 1; /* pointer to data in case we got some */
570
571 if (!_getRequestLine(handler, ¤tLine))
572 return PRT_RETURN_FALSE;
573
574
575 while ((data-currentLine) > 3)
576 {
577 if (!_getHeaderField(handler, ¤tLine))
578 return PRT_RETURN_FALSE;
579
580 }
581
582 /* Check if we have to deal with chunked-encoded data */
583 if (handler->contentLength < 0)
584 {
585 handler->recvievedSize -= index + 1;
586
587 /* Invoke user's callback with header information */
588 {
589 mike 1.1 HttpClient* self = (HttpClient*)handler->base.data;
590
591 if (!(*self->callbackOnResponse)( self, self->callbackData, &handler->recvHeaders,
592 handler->contentLength, handler->contentLength == 0, 0))
593 return PRT_RETURN_FALSE;
594 }
595
596 /* remove consumed header part */
597 memmove(handler->recvBuffer, data, handler->recvievedSize);
598
599 handler->recvingState = RECV_STATE_CHUNKHEADER;
600 return PRT_CONTINUE;
601 }
602
603 /* Allocate zero-terminated buffer */
604 handler->recvPage = (Page*)malloc(sizeof(Page) + (size_t)handler->contentLength + 1);
605
606 if (!handler->recvPage)
607 return PRT_RETURN_FALSE;
608
609 ((char*)(handler->recvPage + 1))[handler->contentLength] = 0;
610 mike 1.1
611 handler->recvPage->u.s.size = (unsigned int)handler->contentLength;
612 handler->recvPage->u.s.next = 0;
613
614 handler->recvievedSize -= index + 1;
615
616 /* Verify that we have not more than 'content-length' bytes in buffer left
617 If we have more, assuming http client is invalid and drop connection */
618 if (handler->recvievedSize > (size_t)handler->contentLength)
619 {
620 LOGW((T("http payload is bigger than content-length\n")));
621 return PRT_RETURN_FALSE;
622 }
623
624 memcpy( handler->recvPage + 1, data, handler->recvievedSize );
625 handler->recvingState = RECV_STATE_CONTENT;
626
627 PRINTF_2(("full header read; page size %d, position %d\n", handler->recvPage->u.s.size, handler->recvievedSize));
628
629 /* Invoke user's callback with header information */
630 {
631 mike 1.1 HttpClient* self = (HttpClient*)handler->base.data;
632
633 if (!(*self->callbackOnResponse)( self, self->callbackData, &handler->recvHeaders,
634 handler->contentLength, handler->contentLength == 0, 0))
635 return PRT_RETURN_FALSE;
636 }
637
638 return PRT_CONTINUE;
639 }
640
641 static Http_CallbackResult _ReadData(
642 Http_SR_SocketData* handler)
643 {
644 //HttpClient* self = (HttpClient*)handler->base.data;
645 char* buf;
646 size_t buf_size, received;
647 MI_Result r;
648
649 /* are we in the right state? */
650 if (handler->recvingState != RECV_STATE_CONTENT)
651 return PRT_RETURN_FALSE;
652 mike 1.1
653 buf = ((char*)(handler->recvPage + 1)) + handler->recvievedSize;
654 buf_size = (size_t)(handler->contentLength - handler->recvievedSize);
655 received = 0;
656
657 if (buf_size)
658 {
659 r = _Sock_Read(handler, buf, buf_size, &received);
660
661 PRINTF(("%d: read r = %d, recv = %d\n", (int)handler->base.sock, (int)r, (int)received ));
662
663 if ( r == MI_RESULT_OK && 0 == received )
664 return PRT_RETURN_FALSE; /* conection closed */
665
666 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
667 return PRT_RETURN_FALSE;
668
669 handler->recvievedSize += received;
670 }
671
672 /* did we get all data? */
673 mike 1.1 PRINTF_2(("dt status - %d / %d\n", (int)handler->recvievedSize, (int)handler->contentLength));
674
675 if ( handler->recvievedSize != (size_t)handler->contentLength )
676 return PRT_RETURN_TRUE;
677
678 /* Invoke user's callback with header information */
679 {
680 HttpClient* self = (HttpClient*)handler->base.data;
681
682 if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
683 handler->contentLength, MI_TRUE, &handler->recvPage))
684 return PRT_RETURN_FALSE;
685
686 /* status callback */
687 handler->status = MI_RESULT_OK;
688 (*self->callbackOnStatus)(
689 self,
690 self->callbackData,
691 MI_RESULT_OK );
692 }
693
694 mike 1.1
695 if (handler->recvPage)
696 free(handler->recvPage);
697
698 handler->recvPage = 0;
699 handler->recvievedSize = 0;
700 memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
701 handler->recvingState = RECV_STATE_HEADER;
702 return PRT_CONTINUE;
703 }
704
705
706 static Http_CallbackResult _ReadChunkHeader(
707 Http_SR_SocketData* handler)
708 {
709 char* buf;
710 char* currentLine;
711 char* data;
712 size_t buf_size, received, index;
713 MI_Result r;
714 MI_Boolean fullHeaderReceived = MI_FALSE;
715 mike 1.1 MI_Uint32 chunkSize = 0;
716 MI_Boolean connectionClosed = MI_FALSE;
717
718 /* are we done with header? */
719 if (handler->recvingState != RECV_STATE_CHUNKHEADER)
720 return PRT_CONTINUE;
721
722 buf = handler->recvBuffer + handler->recvievedSize;
723 buf_size = handler->recvBufferSize - handler->recvievedSize;
724 received = 0;
725
726 r = _Sock_Read(handler, buf, buf_size, &received);
727 PRINTF(("%d: read r = %d, recv = %d; reverse %d\n", (int)handler->base.sock, (int)r, (int)received, (int)handler->reverseOperations ));
728
729 if ( r == MI_RESULT_OK && 0 == received )
730 {
731 if (!handler->recvBufferSize)
732 return PRT_RETURN_FALSE; /* conection closed */
733
734 connectionClosed = MI_TRUE;
735 }
736 mike 1.1
737 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
738 return PRT_RETURN_FALSE;
739
740 if (!received && !handler->recvBufferSize)
741 return PRT_RETURN_TRUE;
742
743 handler->recvievedSize += received;
744
745 /* check header */
746 PRINTF_2(("%s\n",buf));
747
748 /* did we get full header? */
749 buf = handler->recvBuffer;
750 for ( index = 1; index < handler->recvievedSize; index++ )
751 {
752 if (buf[index-1] == '\r' && buf[index] == '\n' )
753 {
754 fullHeaderReceived = MI_TRUE;
755 break;
756 }
757 mike 1.1 }
758
759 if (!fullHeaderReceived )
760 {
761 if (connectionClosed)
762 return PRT_RETURN_FALSE; /* conection closed */
763
764 if ( handler->recvievedSize < handler->recvBufferSize )
765 return PRT_RETURN_TRUE; /* continue reading */
766
767 if ( handler->recvBufferSize < MAX_HEADER_SIZE )
768 {
769 buf = realloc(handler->recvBuffer, handler->recvBufferSize * 2);
770
771 if (!buf)
772 return PRT_RETURN_FALSE;
773
774 handler->recvBufferSize *= 2;
775 handler->recvBuffer = buf;
776 return _ReadChunkHeader(handler);
777 }
778 mike 1.1 else
779 {
780 /* http chunk header is too big - drop connection */
781 LOGW((T("http chunk header is too big; dropping connection\n")));
782 return PRT_RETURN_FALSE;
783 }
784 }
785
786 /* consume data */
787 currentLine = buf;
788 data = buf + index + 1; /* pointer to data in case we got some */
789
790 if (!_getChunkSize(currentLine, &chunkSize))
791 return PRT_RETURN_FALSE;
792
793 if (0 == chunkSize)
794 {
795 /* last chunk received */
796
797 /* Invoke user's callback with header information */
798 {
799 mike 1.1 HttpClient* self = (HttpClient*)handler->base.data;
800
801 if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
802 handler->contentLength, MI_TRUE, 0))
803 return PRT_RETURN_FALSE;
804
805 /* status callback */
806 handler->status = MI_RESULT_OK;
807 (*self->callbackOnStatus)(
808 self,
809 self->callbackData,
810 MI_RESULT_OK );
811 }
812
813 /* clean up state */
814 handler->recvPage = 0;
815 handler->recvievedSize = 0;
816 memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
817 handler->recvingState = RECV_STATE_HEADER;
818
819 if (connectionClosed)
820 mike 1.1 return PRT_RETURN_FALSE; /* conection closed */
821
822 return PRT_CONTINUE;
823 }
824
825 /* Allocate zero-terminated buffer */
826 handler->recvPage = (Page*)malloc(sizeof(Page) + (size_t)chunkSize + 2 /*CR-LF*/ + 1 /* \0 */);
827
828 if (!handler->recvPage)
829 return PRT_RETURN_FALSE;
830
831 ((char*)(handler->recvPage + 1))[chunkSize+2] = 0;
832
833 handler->recvPage->u.s.size = (unsigned int)chunkSize;
834 handler->recvPage->u.s.next = 0;
835
836 /* subtract header size */
837 handler->recvievedSize -= index + 1;
838
839 /* in case of small chunks we may receive more than one chunk already */
840 if (handler->recvievedSize > (size_t)(chunkSize+2))
841 mike 1.1 {
842 /* copy page size to page */
843 memcpy( handler->recvPage + 1, data, chunkSize+2 );
844
845 /* notify user */
846 {
847 HttpClient* self = (HttpClient*)handler->base.data;
848
849 if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
850 handler->contentLength, MI_FALSE, &handler->recvPage))
851 return PRT_RETURN_FALSE;
852
853 if (handler->recvPage)
854 free(handler->recvPage);
855
856 handler->recvPage = 0;
857 }
858
859 /* remove consumed part */
860 memmove(handler->recvBuffer, data + chunkSize+2, handler->recvievedSize - (chunkSize+2));
861 handler->recvievedSize -= (chunkSize+2);
862 mike 1.1
863 /* consume next chunk */
864 return _ReadChunkHeader(handler);
865 }
866
867 memcpy( handler->recvPage + 1, data, handler->recvievedSize );
868 handler->recvingState = RECV_STATE_CHUNKDATA;
869
870 if (connectionClosed)
871 return PRT_RETURN_FALSE; /* conection closed */
872
873 return PRT_CONTINUE;
874 }
875 static Http_CallbackResult _ReadChunkData(
876 Http_SR_SocketData* handler)
877 {
878 //HttpClient* self = (HttpClient*)handler->base.data;
879 char* buf;
880 size_t buf_size, received;
881 MI_Result r;
882
883 mike 1.1 /* are we in the right state? */
884 if (handler->recvingState != RECV_STATE_CHUNKDATA)
885 return PRT_RETURN_FALSE;
886
887 buf = ((char*)(handler->recvPage + 1)) + handler->recvievedSize;
888 buf_size = (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */ - handler->recvievedSize);
889 received = 0;
890
891 if (buf_size)
892 {
893 r = _Sock_Read(handler, buf, buf_size, &received);
894
895 PRINTF(("%d: read r = %d, recv = %d\n", (int)handler->base.sock, (int)r, (int)received ));
896
897 if ( r == MI_RESULT_OK && 0 == received )
898 return PRT_RETURN_FALSE; /* conection closed */
899
900 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
901 return PRT_RETURN_FALSE;
902
903 handler->recvievedSize += received;
904 mike 1.1 }
905
906 /* did we get all data? */
907 PRINTF_2(("dt status - %d / %d\n", (int)handler->recvievedSize, (int)handler->contentLength));
908
909 if ( handler->recvievedSize != (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */) )
910 return PRT_RETURN_TRUE;
911
912 /* Invoke user's callback with header information */
913 {
914 HttpClient* self = (HttpClient*)handler->base.data;
915
916 if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
917 handler->contentLength, MI_FALSE, &handler->recvPage))
918 return PRT_RETURN_FALSE;
919
920 }
921
922
923 if (handler->recvPage)
924 free(handler->recvPage);
925 mike 1.1
926 handler->recvPage = 0;
927 handler->recvievedSize = 0;
928 memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
929 handler->recvingState = RECV_STATE_CHUNKHEADER;
930 return PRT_CONTINUE;
931 }
932
933
934 static Http_CallbackResult _WriteHeader(
935 Http_SR_SocketData* handler)
936 {
937 char* buf;
938 size_t buf_size, sent;
939 MI_Result r;
940
941 /* Do we have any data to send? */
942 if (!handler->sendHeader)
943 return PRT_RETURN_TRUE;
944
945 /* are we done with header? */
946 mike 1.1 if (handler->sendingState == RECV_STATE_CONTENT)
947 return PRT_CONTINUE;
948
949 buf = ((char*)(handler->sendHeader + 1)) + handler->sentSize;
950 buf_size = handler->sendHeader->u.s.size - handler->sentSize;
951 sent = 0;
952
953 r = _Sock_Write(handler, buf, buf_size, &sent);
954
955 PRINTF(("%d: write r = %d, sent = %d\n", (int)handler->base.sock, (int)r, (int)sent ));
956
957 if ( r == MI_RESULT_OK && 0 == sent )
958 return PRT_RETURN_FALSE; /* conection closed */
959
960 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
961 return PRT_RETURN_FALSE;
962
963 handler->sentSize += sent;
964
965 /* did we get all data? */
966
967 mike 1.1 if ( handler->sentSize != handler->sendHeader->u.s.size )
968 return PRT_RETURN_TRUE;
969
970 free(handler->sendHeader);
971 handler->sendHeader = 0;
972 handler->sentSize = 0;
973 handler->sendingState = RECV_STATE_CONTENT;
974
975 return PRT_CONTINUE;
976 }
977
978 static Http_CallbackResult _WriteData(
979 Http_SR_SocketData* handler)
980 {
981 char* buf;
982 size_t buf_size, sent;
983 MI_Result r;
984
985 /* are we in the right state? */
986 if (handler->sendingState != RECV_STATE_CONTENT)
987 return PRT_RETURN_FALSE;
988 mike 1.1
989 if (!handler->sendPage)
990 { /* no content*/
991 handler->sentSize = 0;
992 handler->sendingState = RECV_STATE_HEADER;
993 handler->base.mask &= ~SELECTOR_WRITE;
994 handler->base.mask |= SELECTOR_READ;
995
996 return PRT_CONTINUE;
997 }
998
999 buf = ((char*)(handler->sendPage + 1)) + handler->sentSize;
1000 buf_size = handler->sendPage->u.s.size - handler->sentSize;
1001 sent = 0;
1002
1003 r = _Sock_Write(handler, buf, buf_size, &sent);
1004
1005 PRINTF(("%d: write r = %d, sent = %d\n", (int)handler->base.sock, (int)r, (int)sent ));
1006
1007 if ( r == MI_RESULT_OK && 0 == sent )
1008 return PRT_RETURN_FALSE; /* conection closed */
1009 mike 1.1
1010 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
1011 return PRT_RETURN_FALSE;
1012
1013 handler->sentSize += sent;
1014
1015 /* did we get all data? */
1016
1017 if ( handler->sentSize != handler->sendPage->u.s.size )
1018 return PRT_RETURN_TRUE;
1019
1020 free(handler->sendPage);
1021 handler->sendPage = 0;
1022 handler->sentSize = 0;
1023 handler->sendingState = RECV_STATE_HEADER;
1024 handler->base.mask &= ~SELECTOR_WRITE;
1025 handler->base.mask |= SELECTOR_READ;
1026
1027 return PRT_CONTINUE;
1028 }
1029
1030 mike 1.1
1031 static MI_Boolean _RequestCallbackRead(
1032 Http_SR_SocketData* handler)
1033 {
1034 switch (_ReadHeader(handler))
1035 {
1036 case PRT_CONTINUE: break;
1037 case PRT_RETURN_TRUE: return MI_TRUE;
1038 case PRT_RETURN_FALSE: return MI_FALSE;
1039 }
1040
1041 if (handler->recvingState == RECV_STATE_CONTENT)
1042 {
1043 switch (_ReadData(handler))
1044 {
1045 case PRT_CONTINUE: break;
1046 case PRT_RETURN_TRUE: return MI_TRUE;
1047 case PRT_RETURN_FALSE: return MI_FALSE;
1048 }
1049 }
1050
1051 mike 1.1 if (handler->recvingState == RECV_STATE_CHUNKHEADER)
1052 {
1053 switch (_ReadChunkHeader(handler))
1054 {
1055 case PRT_CONTINUE: break;
1056 case PRT_RETURN_TRUE: return MI_TRUE;
1057 case PRT_RETURN_FALSE: return MI_FALSE;
1058 }
1059 }
1060 if (handler->recvingState == RECV_STATE_CHUNKDATA)
1061 {
1062 switch (_ReadChunkData(handler))
1063 {
1064 case PRT_CONTINUE: break;
1065 case PRT_RETURN_TRUE: return MI_TRUE;
1066 case PRT_RETURN_FALSE: return MI_FALSE;
1067 }
1068 }
1069
1070 return MI_TRUE;
1071 }
1072 mike 1.1
1073 static MI_Boolean _RequestCallbackWrite(
1074 Http_SR_SocketData* handler)
1075 {
1076 switch (_WriteHeader(handler))
1077 {
1078 case PRT_CONTINUE: break;
1079 case PRT_RETURN_TRUE: return MI_TRUE;
1080 case PRT_RETURN_FALSE: return MI_FALSE;
1081 }
1082
1083 switch (_WriteData(handler))
1084 {
1085 case PRT_CONTINUE: break;
1086 case PRT_RETURN_TRUE: return MI_TRUE;
1087 case PRT_RETURN_FALSE: return MI_FALSE;
1088 }
1089 return MI_TRUE;
1090 }
1091
1092
1093 mike 1.1 static MI_Boolean _RequestCallback(
1094 Selector* sel,
1095 Handler* handlerIn,
1096 MI_Uint32 mask,
1097 MI_Uint64 currentTimeUsec)
1098 {
1099 Http_SR_SocketData* handler = (Http_SR_SocketData*)handlerIn;
1100 sel=sel;
1101
1102 if ( ((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||
1103 ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations) )
1104 {
1105 if (!_RequestCallbackRead(handler))
1106 return MI_FALSE;
1107 }
1108
1109 if ( ((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||
1110 ((mask & SELECTOR_READ) != 0 && handler->reverseOperations) )
1111 {
1112 if (!_RequestCallbackWrite(handler))
1113 return MI_FALSE;
1114 mike 1.1 }
1115
1116 /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */
1117 if (mask & (SELECTOR_READ | SELECTOR_WRITE))
1118 {
1119 handler->base.fireTimeoutAt = currentTimeUsec + handler->timeoutUsec;
1120 }
1121
1122 /* Close conenction by timeout */
1123 if (mask & SELECTOR_TIMEOUT)
1124 {
1125 if (MI_RESULT_OK != handler->status)
1126 handler->status = MI_RESULT_TIME_OUT;
1127
1128 return MI_FALSE;
1129 }
1130
1131 if ((mask & SELECTOR_REMOVE) != 0 ||
1132 (mask & SELECTOR_DESTROY) != 0)
1133 {
1134 HttpClient* self = (HttpClient*)handler->base.data;
1135 mike 1.1
1136 /* notify next stack layer */
1137 if (MI_RESULT_OK != handler->status)
1138 (*self->callbackOnStatus)(
1139 self,
1140 self->callbackData,
1141 handler->status);
1142
1143 self->connector = 0;
1144
1145 if (handler->ssl)
1146 SSL_free(handler->ssl);
1147
1148 PRINTF(("%d: close\n", (int)handler->base.sock));
1149
1150 Sock_Close(handler->base.sock);
1151
1152 if (handler->recvPage)
1153 free(handler->recvPage);
1154
1155 if (handler->sendPage)
1156 mike 1.1 free(handler->sendPage);
1157
1158 if (handler->sendHeader)
1159 free(handler->sendHeader);
1160
1161 free(handler->recvBuffer);
1162 free(handler);
1163 }
1164
1165 return MI_TRUE;
1166 }
1167
1168 #ifdef CONFIG_POSIX
1169 static MI_Result _CreateSSLContext(HttpClient* self)
1170 {
1171 SSL_CTX * sslContext = 0;
1172
1173 sslContext = SSL_CTX_new(SSLv23_method());
1174
1175 if (!sslContext)
1176 {
1177 mike 1.1 LOGE_CHAR((
1178 "---> SSL: cannot create ssl context"));
1179 return MI_RESULT_FAILED;
1180 }
1181 SSL_CTX_set_quiet_shutdown(sslContext, 1);
1182 SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
1183 SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);
1184 SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
1185 #if 0
1186 /* Check if there is a certificate file (file containing server
1187 ** certificate) specified. If specified, validate and load the
1188 ** certificate.
1189 */
1190 {
1191 /* load the specified server certificates */
1192 LOGI_CHAR(("---> SSL: Loading server certificate from: %s",
1193 GetPath(ID_PEMFILE)));
1194
1195 if (SSL_CTX_use_certificate_file(sslContext,
1196 GetPath(ID_PEMFILE), SSL_FILETYPE_PEM) <=0)
1197 {
1198 mike 1.1 LOGE_CHAR(("---> SSL: No server certificate found in %s",
1199 GetPath(ID_PEMFILE)));
1200 SSL_CTX_free(sslContext);
1201 return MI_RESULT_FAILED;
1202 }
1203 }
1204
1205 /*
1206 ** Check if there is a key file (file containing server
1207 ** private key) specified and the key was not already loaded.
1208 ** If specified, validate and load the key.
1209 */
1210 {
1211 /* load the specified server certificates */
1212 LOGI_CHAR(("---> SSL: Loading certificate's private key from: %s",
1213 GetPath(ID_KEYFILE)));
1214
1215 //
1216 // load given private key and check for validity
1217 //
1218 if (!_verifyPrivateKey(sslContext, GetPath(ID_KEYFILE)))
1219 mike 1.1 {
1220 LOGE_CHAR((
1221 "---> SSL: No server certificate found in %s",
1222 GetPath(ID_KEYFILE)));
1223 SSL_CTX_free(sslContext);
1224 return MI_RESULT_FAILED;
1225 }
1226 }
1227 #endif
1228 self->sslContext = sslContext;
1229 return MI_RESULT_OK;
1230 }
1231 #endif
1232
1233 static MI_Result _CreateConnectorSocket(
1234 HttpClient* self,
1235 const char* host,
1236 unsigned short port,
1237 MI_Boolean secure)
1238 {
1239 Addr addr;
1240 mike 1.1 MI_Result r;
1241 Sock s;
1242 Http_SR_SocketData* h;
1243 MI_Uint64 currentTimeUsec;
1244
1245 /* timeout calculation */
1246 if (MI_RESULT_OK != Time_Now(¤tTimeUsec))
1247 return MI_RESULT_FAILED;
1248
1249 // Initialize address.
1250 r = Addr_Init(&addr, host, port);
1251 if (r != MI_RESULT_OK)
1252 return MI_RESULT_FAILED;
1253
1254 // Create client socket.
1255 r = Sock_Create(&s);
1256 if (r != MI_RESULT_OK)
1257 {
1258 Sock_Close(s);
1259 return MI_RESULT_FAILED;
1260 }
1261 mike 1.1
1262 r = Sock_SetBlocking(s, MI_FALSE);
1263 if (r != MI_RESULT_OK)
1264 {
1265 Sock_Close(s);
1266 return MI_RESULT_FAILED;
1267 }
1268
1269 // Connect to the server.
1270 r = Sock_Connect(s, &addr);
1271 if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1272 {
1273 Sock_Close(s);
1274 return MI_RESULT_FAILED;
1275 }
1276
1277 /* Create handler */
1278 h = (Http_SR_SocketData*)calloc(1, sizeof(Http_SR_SocketData));
1279
1280 if (!h)
1281 {
1282 mike 1.1 Sock_Close(s);
1283 return MI_RESULT_FAILED;
1284 }
1285
1286 h->recvBufferSize = INITIAL_BUFFER_SIZE;
1287 h->recvBuffer = (char*)calloc(1, h->recvBufferSize);
1288 if (!h->recvBuffer)
1289 {
1290 free(h);
1291 Sock_Close(s);
1292 return MI_RESULT_FAILED;
1293 }
1294
1295 h->base.sock = s;
1296 h->base.mask = SELECTOR_EXCEPTION;
1297 h->base.callback = _RequestCallback;
1298 h->base.data = self;
1299 h->timeoutUsec = DEFAULT_HTTP_TIMEOUT_USEC;
1300 h->base.fireTimeoutAt = currentTimeUsec + h->timeoutUsec;
1301
1302 /* ssl support */
1303 mike 1.1 if (secure)
1304 {
1305 h->ssl = SSL_new(self->sslContext);
1306
1307 if (!h->ssl)
1308 {
1309 LOGW((T("ssl_new() failed\n")));
1310 free(h);
1311 Sock_Close(s);
1312 return MI_RESULT_FAILED;
1313 }
1314
1315 if (!(SSL_set_fd(h->ssl, s) ))
1316 {
1317 LOGW((T("ssl_set_fd() failed\n")));
1318 SSL_free(h->ssl);
1319 free(h);
1320 Sock_Close(s);
1321 return MI_RESULT_FAILED;
1322 }
1323
1324 mike 1.1 SSL_set_connect_state(h->ssl);
1325 }
1326
1327 /* Watch for read events on the incoming connection */
1328 r = Selector_AddHandler(self->selector, &h->base);
1329
1330 if (r != MI_RESULT_OK)
1331 {
1332 LOGW((T("Selector_AddHandler() failed\n")));
1333 if (secure)
1334 SSL_free(h->ssl);
1335 free(h);
1336 Sock_Close(s);
1337 return MI_RESULT_FAILED;
1338 }
1339
1340 self->connector = h;
1341
1342 return MI_RESULT_OK;
1343 }
1344
1345 mike 1.1
1346 static MI_Result _New_Http(
1347 HttpClient** selfOut,
1348 Selector* selector, /*optional, maybe NULL*/
1349 HttpClientCallbackOnStatus statusCallback,
1350 HttpClientCallbackOnResponse responseCallback,
1351 void* callbackData)
1352 {
1353 HttpClient* self;
1354
1355 /* Check parameters */
1356 if (!selfOut)
1357 return MI_RESULT_INVALID_PARAMETER;
1358
1359 /* Clear output parameter */
1360 *selfOut = NULL;
1361
1362 /* Allocate structure */
1363 {
1364 self = (HttpClient*)calloc(1, sizeof(HttpClient));
1365
1366 mike 1.1 if (!self)
1367 return MI_RESULT_FAILED;
1368 }
1369
1370 if (selector)
1371 { /* attach the exisiting selector */
1372 self->selector = selector;
1373 self->internalSelectorUsed = MI_FALSE;
1374 }
1375 else
1376 { /* creaet a new selector */
1377 /* Initialize the network */
1378 Sock_Start();
1379
1380 /* Initialize the selector */
1381 if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)
1382 {
1383 free(self);
1384 return MI_RESULT_FAILED;
1385 }
1386 self->selector = &self->internalSelector;
1387 mike 1.1 self->internalSelectorUsed = MI_TRUE;
1388 }
1389
1390 /* Save the callback and callbackData */
1391 self->callbackOnResponse = responseCallback;
1392 self->callbackOnStatus = statusCallback;
1393 self->callbackData = callbackData;
1394
1395 /* Set the magic number */
1396 self->magic = _MAGIC;
1397
1398 /* Set output parameter */
1399 *selfOut = self;
1400 return MI_RESULT_OK;
1401 }
1402
1403
1404
1405 static size_t _GetHeadersSize(
1406 const HttpClientRequestHeaders* headers)
1407 {
1408 mike 1.1 size_t res = 0;
1409 size_t index = 0;
1410
1411 while (index < headers->size)
1412 {
1413 res += Strlen(headers->data[index]);
1414 res += 2; /* \r \n pair */
1415 index++;
1416 }
1417
1418 return res;
1419 }
1420
1421 static Page* _CreateHttpHeader(
1422 const char* verb,
1423 const char* uri,
1424 const HttpClientRequestHeaders* headers,
1425 size_t size)
1426 {
1427 Page* page = 0;
1428 size_t pageSize = 0;
1429 mike 1.1 int r;
1430 char* p;
1431
1432 #define HTTP_HEADER_FORMAT "%s %s HTTP/1.1\r\n" \
1433 "Content-Length: %d\r\n"\
1434 "Connection: Keep-Alive\r\n" \
1435 "Host: host\r\n"
1436
1437 #define HTTP_HEADER_FORMAT_NOCL "%s %s HTTP/1.1\r\n" \
1438 "Connection: Keep-Alive\r\n" \
1439 "Host: host\r\n"
1440
1441 /* calculate approximate page size */
1442 if (!verb)
1443 verb = "POST";
1444 pageSize += sizeof(HTTP_HEADER_FORMAT) + 10; /* format + 10 digits of content length */
1445 pageSize += Strlen(verb);
1446 pageSize += Strlen(uri);
1447
1448 if (headers)
1449 pageSize += _GetHeadersSize(headers);
1450 mike 1.1
1451 page = (Page*)malloc(pageSize + sizeof(Page));
1452
1453 if (!page)
1454 return 0;
1455
1456 /* clear header */
1457 memset(page, 0, sizeof(Page));
1458
1459 p = (char*)(page + 1);
1460
1461 if (size)
1462 r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT, verb, uri, (int)size);
1463 else
1464 r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT_NOCL, verb, uri);
1465
1466 if (r < 0)
1467 {
1468 free(page);
1469 return 0;
1470 }
1471 mike 1.1
1472 p += r;
1473 pageSize -= r;
1474
1475 if (headers)
1476 {
1477 size_t index = 0;
1478
1479 while (index < headers->size)
1480 {
1481 r = (int)Strlcpy(p,headers->data[index], pageSize);
1482 p += r;
1483 pageSize -= r;
1484 r = (int)Strlcpy(p,"\r\n", pageSize);
1485 p += r;
1486 pageSize -= r;
1487
1488 index++;
1489 }
1490 }
1491
1492 mike 1.1 /* add trailing \r\n */
1493 r = (int)Strlcpy(p,"\r\n", pageSize);
1494 p += r;
1495 pageSize -= r;
1496
1497 page->u.s.size = (unsigned int)(p - (char*)(page+1));
1498
1499 return page;
1500 }
1501
1502 /* ************************************************************************* *\
1503 HTTP CLIENT
1504 \* ************************************************************************* */
1505 /*
1506 Creates new http client.
1507
1508 Parameters:
1509 selfOut - [out] newly created http object (or null if failed).
1510 selector - [opt] selector to use for socket monitoring. If selector not specified,
1511 private one is created.
1512 host - host address
1513 mike 1.1 port - port number
1514 secure - flag that indicates if http or https conneciton is required
1515
1516 Returns:
1517 'OK' on success or error code otherwise
1518 */
1519 MI_Result HttpClient_New_Connector(
1520 HttpClient** selfOut,
1521 Selector* selector, /*optional, maybe NULL*/
1522 const char* host,
1523 unsigned short port,
1524 MI_Boolean secure,
1525 HttpClientCallbackOnStatus statusCallback,
1526 HttpClientCallbackOnResponse responseCallback,
1527 void* callbackData)
1528 {
1529 HttpClient* self;
1530 MI_Result r;
1531
1532 /* allocate this, inits selector */
1533 r = _New_Http(selfOut, selector, statusCallback,
1534 mike 1.1 responseCallback, callbackData);
1535
1536 if (MI_RESULT_OK != r)
1537 return r;
1538
1539 self = *selfOut;
1540
1541 #ifdef CONFIG_POSIX
1542 /* Allocate ssl context */
1543 if (secure)
1544 {
1545 /* init ssl */
1546 SSL_library_init();
1547
1548 /* create context */
1549 r = _CreateSSLContext(self);
1550
1551 if (r != MI_RESULT_OK)
1552 {
1553 HttpClient_Delete(self);
1554 return r;
1555 mike 1.1 }
1556 }
1557 #else
1558 MI_UNUSED(secure);
1559 #endif
1560
1561 /* Create http connector socket */
1562 {
1563 r = _CreateConnectorSocket(self, host, port, secure);
1564
1565 if (r != MI_RESULT_OK)
1566 {
1567 HttpClient_Delete(self);
1568 return r;
1569 }
1570 }
1571
1572
1573 return MI_RESULT_OK;
1574 }
1575
1576 mike 1.1 /*
1577 Deletes http object, disconnects form the server
1578 and frees all related resources.
1579
1580 Parameters:
1581 self - http object
1582
1583 Returns:
1584 OK
1585 */
1586 MI_Result HttpClient_Delete(
1587 HttpClient* self)
1588 {
1589 /* Check parameters */
1590 if (!self)
1591 return MI_RESULT_INVALID_PARAMETER;
1592
1593 /* Check magic number */
1594 if (self->magic != _MAGIC)
1595 return MI_RESULT_INVALID_PARAMETER;
1596
1597 mike 1.1 if (self->internalSelectorUsed)
1598 {
1599 /* Release selector;
1600 Note: selector-destory closes all sockects in a list including connector and listener */
1601 Selector_Destroy(self->selector);
1602
1603 /* Shutdown the network */
1604 Sock_Stop();
1605 }
1606 else
1607 {
1608 /* remove connector from handler */
1609 if (self->connector)
1610 Selector_RemoveHandler(self->selector, &self->connector->base);
1611 }
1612
1613 if (self->sslContext)
1614 SSL_CTX_free(self->sslContext);
1615
1616 /* Clear magic number */
1617 self->magic = 0xDDDDDDDD;
1618 mike 1.1
1619 /* Free self pointer */
1620 free(self);
1621
1622 return MI_RESULT_OK;
1623 }
1624
1625
1626 /*
1627 Sends http request.
1628
1629 Parameters:
1630 self - http object
1631 uri - request's URI
1632 headers - [opt] extra headers for request.
1633 data - [opt] content to send. if message is accepted to be sent,
1634 on return *data == null (taking memory ownership)
1635
1636 Returns:
1637 OK or appropriate error
1638 */
1639 mike 1.1 MI_Result HttpClient_StartRequest(
1640 HttpClient* self,
1641 const char* verb,
1642 const char* uri,
1643 const HttpClientRequestHeaders* headers,
1644 Page** data)
1645 {
1646
1647 /* check params */
1648 if (!self || !uri)
1649 return MI_RESULT_INVALID_PARAMETER;
1650
1651 if (self->magic != _MAGIC)
1652 {
1653 LOGW((T("start-request: invalid magic!") ));
1654 return MI_RESULT_INVALID_PARAMETER;
1655 }
1656
1657 if (!self->connector)
1658 {
1659 LOGW((T("start-request: connection was closed") ));
1660 mike 1.1 return MI_RESULT_FAILED;
1661 }
1662
1663 /* create header page */
1664 self->connector->sendHeader =
1665 _CreateHttpHeader(verb, uri, headers, (data && *data) ? (*data)->u.s.size : 0);
1666
1667 if (data)
1668 {
1669 self->connector->sendPage = *data;
1670 *data = 0;
1671 }
1672 else
1673 {
1674 self->connector->sendPage = 0;
1675 }
1676
1677 /* set status to failed, until we know more details */
1678 self->connector->status = MI_RESULT_FAILED;
1679 self->connector->sentSize = 0;
1680 self->connector->sendingState = RECV_STATE_HEADER;
1681 mike 1.1 self->connector->base.mask |= SELECTOR_WRITE;
1682
1683 _RequestCallbackWrite(self->connector);
1684
1685 return MI_RESULT_OK;
1686 }
1687
1688
1689 MI_Result HttpClient_Run(
1690 HttpClient* self,
1691 MI_Uint64 timeoutUsec)
1692 {
1693 /* Run the selector */
1694 return Selector_Run(self->selector, timeoutUsec);
1695 }
1696
1697 MI_Result HttpClient_SetTimeout(
1698 HttpClient* self,
1699 MI_Uint64 timeoutUsec)
1700 {
1701 MI_Uint64 currentTimeUsec = 0;
1702 mike 1.1
1703 Time_Now(¤tTimeUsec);
1704
1705 /* check params */
1706 if (!self)
1707 return MI_RESULT_INVALID_PARAMETER;
1708
1709 if (self->magic != _MAGIC)
1710 {
1711 LOGW((T("setTimeout: invalid magic!") ));
1712 return MI_RESULT_INVALID_PARAMETER;
1713 }
1714
1715 if (!self->connector)
1716 return MI_RESULT_INVALID_PARAMETER;
1717
1718 /* create header page */
1719 self->connector->timeoutUsec = timeoutUsec;
1720 self->connector->base.fireTimeoutAt = currentTimeUsec + self->connector->timeoutUsec;
1721
1722 return MI_RESULT_OK;
1723 mike 1.1 }
1724
1725
|