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