1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
|
8 krisbash 1.4 ** 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.4 ** 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.4 ** 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 <sock/addr.h>
29 #include <sock/sock.h>
30 #include <sock/selector.h>
|
31 krisbash 1.3 #include <pal/sleep.h>
|
32 krisbash 1.4 #include <pal/intsafe.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 mike 1.1 #include <base/paths.h>
|
39 krisbash 1.3 #include <base/Strand.h>
|
40 mike 1.1
41 #ifdef CONFIG_POSIX
42 #include <openssl/ssl.h>
43 #include <openssl/err.h>
44 #include <pthread.h>
45 #else
46 /* ssl not supported in this configuration; just make compiler happy */
47 typedef void SSL;
48 typedef void SSL_CTX;
49 #define SSL_CTX_free(c)
50 #define SSL_new(c) 0
51 #define SSL_free(c)
52 #define SSL_set_fd(c,a) (a==a)
53 #define SSL_read(c,a,b) 0
54 #define SSL_write(c,a,b) 0
55 #define SSL_get_error(c,e) e
56 #define SSL_ERROR_WANT_WRITE 0
57 #define SSL_ERROR_WANT_READ 1
58 #define SSL_ERROR_SYSCALL 2
59
60 #ifdef EWOULDBLOCK
61 mike 1.1 # undef EWOULDBLOCK
62 #endif
63 #define EWOULDBLOCK 0
64
65 #ifdef EINPROGRESS
66 # undef EINPROGRESS
67 #endif
68 #define EINPROGRESS 0
69
70 #define ERR_get_error() 0
71 #define ERR_error_string_n(c,a,b) a[0]=0
72 #define SSL_accept(c) 0
73
74 #endif
75
|
76 krisbash 1.3 #define FORCE_TRACING 0
|
77 mike 1.1
|
78 krisbash 1.3 //------------------------------------------------------------------------------
|
79 mike 1.1
|
80 krisbash 1.3 #define HTTPSOCKET_STRANDAUX_NEWREQUEST 0
|
81 mike 1.1
|
82 krisbash 1.3 STRAND_DEBUGNAME1( HttpSocket, NewRequest );
|
83 mike 1.1
84 /*
85 **==============================================================================
86 **
87 ** Local definitions:
88 **
89 **==============================================================================
90 */
91
92 static const MI_Uint32 _MAGIC = 0xE0BB5FD3;
93 static const MI_Uint32 MAX_HEADER_SIZE = 2 * 1024;
94 static const MI_Uint32 INITIAL_BUFFER_SIZE = 2 * 1024;
95 static const size_t HTTP_MAX_CONTENT = 1024 * 1024;
96
97 struct _Http
98 {
|
99 krisbash 1.3 MI_Uint32 magic;
|
100 mike 1.1 Selector internalSelector;
101 Selector* selector;
|
102 krisbash 1.3 OpenCallback callbackOnNewConnection;
103 void* callbackData;
104 SSL_CTX* sslContext;
|
105 mike 1.1 /* options: timeouts etc */
106 HttpOptions options;
|
107 krisbash 1.3 MI_Boolean internalSelectorUsed;
|
108 mike 1.1 };
109
110 typedef struct _Http_Listener_SocketData
111 {
112 /* based member*/
113 Handler base;
114
115 MI_Boolean secure;
116 }
117 Http_Listener_SocketData;
118
119 typedef enum _Http_RecvState
120 {
121 RECV_STATE_HEADER,
122 RECV_STATE_CONTENT
123 }
124 Http_RecvState;
125
126 typedef struct _Http_SR_SocketData
127 {
|
128 krisbash 1.3 Strand strand;
|
129 krisbash 1.4
|
130 krisbash 1.3 Handler handler; // Used on selector
131
132 Http* http;
|
133 mike 1.1
134 /* ssl part */
135 SSL* ssl;
136 MI_Boolean reverseOperations; /*reverse read/write Events/Handlers*/
137 MI_Boolean acceptDone;
138
|
139 krisbash 1.4 /* is server/provider is processing request
|
140 mike 1.1 (to disbale timeout) */
141 MI_Boolean requestIsBeingProcessed;
142
143 /* receiving data */
144 char* recvBuffer;
145 size_t recvBufferSize;
|
146 krisbash 1.3 size_t receivedSize;
|
147 mike 1.1 Http_RecvState recvingState;
148 HttpHeaders recvHeaders;
149 Page* recvPage;
|
150 krisbash 1.3 HttpRequestMsg* request; // request msg with the request page
|
151 mike 1.1
152 /* sending part */
153 Page* sendPage;
154 size_t sentSize;
155 Http_RecvState sendingState;
156 int httpErrorCode;
157
|
158 krisbash 1.3 /* pending send message */
159 Message* savedSendMsg;
160
|
161 mike 1.1 /* Enable tracing */
162 MI_Boolean enableTracing;
163 }
164 Http_SR_SocketData;
165
166 /* helper functions result */
167 typedef enum _Http_CallbackResult
168 {
169 PRT_CONTINUE,
170 PRT_RETURN_TRUE,
171 PRT_RETURN_FALSE
172 }
173 Http_CallbackResult;
174
175 MI_INLINE MI_Uint8 _ToLower(MI_Uint8 x)
176 {
177 return (MI_Uint8)tolower(x);
178 }
179
180 #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8) | (((MI_Uint16)len)) )
181
|
182 krisbash 1.3 _Return_type_success_(return == MI_TRUE)
|
183 mike 1.1 static MI_Boolean _getNameValuePair(
|
184 krisbash 1.3 _Inout_ CharPtr* line,
185 _Out_ CharPtr* value,
|
186 mike 1.1 int* nameHashCode )
187 {
188 int len = 0;
189 char* p;
|
190 krisbash 1.3 *value = 0;
|
191 mike 1.1 /* find name end /hash-code */
192
|
193 krisbash 1.3 if ((*line)[0] == 0)
194 {
195 trace_GetNameValuePair_Failed();
196 return MI_FALSE;
197 }
198
|
199 mike 1.1 *nameHashCode = _ToLower((MI_Uint8)(*line)[0])<<16;
200
|
201 krisbash 1.3 for (len = 1; (*line)[len] && (*line)[len] != ':' && (*line)[len] != '\r'; len++ )
|
202 mike 1.1 ;
203
204 if ((*line)[len] != ':')
|
205 krisbash 1.3 {
206 trace_GetNameValuePair_Failed();
|
207 mike 1.1 return MI_FALSE;
|
208 krisbash 1.3 }
|
209 mike 1.1
210 *nameHashCode |= (len) | _ToLower((MI_Uint8)(*line)[len-1])<<8;
211 (*line)[len] = 0;
212 p = *line + len + 1;
213
214 /* skip spaces in value */
215 while (p[0] == ' ' || p[0] == '\t')
216 p++;
217
218 *value = p;
219
220 /* skip to end of line */
|
221 krisbash 1.3 for ( ; p[0]; )
|
222 mike 1.1 {
|
223 krisbash 1.4 if (p[0] == '\r' && p[1] == '\n' &&
|
224 mike 1.1 (p[2] != ' ' && p[2] != '\t') )
225 {
226 p[0] = 0;
227 (*line) = p + 2;
228 break;
229 }
230 p ++;
231 }
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 p[1] = 0;
247
248 return MI_TRUE;
249 }
250
251 static MI_Boolean _getHeaderField(
252 Http_SR_SocketData* handler,
|
253 krisbash 1.3 _Inout_ CharPtr* line)
|
254 mike 1.1 {
255 char* name = *line;
256 char* value = NULL;
257 int nameHashCode;
258
259 if (!_getNameValuePair(line, &value, &nameHashCode))
|
260 krisbash 1.3 {
261 trace_GetNameValuePair_Failed();
|
262 mike 1.1 return MI_FALSE;
|
263 krisbash 1.3 }
264
265
266 #if defined(CONFIG_ENABLE_HTTPHEADERS)
|
267 mike 1.1
|
268 krisbash 1.3 /* Inject name-value into HTTP header array */
|
269 mike 1.1
|
270 krisbash 1.3 if (handler->recvHeaders.headersSize < HTTP_MAX_HEADERS)
|
271 mike 1.1 {
|
272 krisbash 1.3 handler->recvHeaders.headers[handler->recvHeaders.headersSize].name =
273 name;
274 handler->recvHeaders.headers[handler->recvHeaders.headersSize].value =
275 value;
276 handler->recvHeaders.headersSize++;
277 }
278
279 #endif /* defined(CONFIG_ENABLE_HTTPHEADERS) */
|
280 mike 1.1
|
281 krisbash 1.3 /* Convert specified headers to static fields */
|
282 mike 1.1
|
283 krisbash 1.3 switch (nameHashCode)
284 {
285 case (_HashCode('c','e',12)): /*Content-Type*/
|
286 mike 1.1 {
|
287 krisbash 1.3 if (Strcasecmp(name,"Content-Type") == 0)
288 ParseContentType(&handler->recvHeaders, value);
289
290 break;
|
291 mike 1.1 }
|
292 krisbash 1.3 case (_HashCode('c','h',14)): /*Content-Length*/
293 {
294 if (Strcasecmp(name,"Content-Length") == 0)
295 {
|
296 krisbash 1.4 handler->recvHeaders.contentLength = (size_t)Strtoull(value,
|
297 krisbash 1.3 NULL, 10);
|
298 mike 1.1
|
299 krisbash 1.3 if ( handler->recvHeaders.contentLength > HTTP_MAX_CONTENT )
300 {
301 trace_ContentLength_MaxCheck_Failed();
302 return MI_FALSE;
303 }
304 }
305 break;
306 }
307 case (_HashCode('a','n',13)): /*Authorization*/
|
308 mike 1.1 {
|
309 krisbash 1.3 if (Strcasecmp(name,"Authorization") == 0)
|
310 mike 1.1 {
|
311 krisbash 1.3 if( !ParseAuthorization(&handler->recvHeaders,value) )
|
312 mike 1.1 {
313 return MI_FALSE;
314 }
315 }
|
316 krisbash 1.3 break;
|
317 mike 1.1 }
|
318 krisbash 1.3 case (_HashCode('u','t',10)):
319 {
320 /* Remember the User-Agent for later use */
321 if (Strcasecmp(name, "User-Agent") == 0)
322 {
323 handler->recvHeaders.userAgent = value;
324 }
325 break;
326 }
327 default:
328 break;
|
329 mike 1.1
330 }
331
332 return MI_TRUE;
333 }
334
335 static MI_Boolean _getRequestLine(
336 Http_SR_SocketData* handler,
|
337 krisbash 1.3 _Inout_ CharPtr* line)
|
338 mike 1.1 {
339 size_t index;
340 /* expecting Request-Line = Method SP Request-URI SP HTTP-Version CRLF
341 Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
342 */
343
|
344 krisbash 1.3 if ((*line)[0] == 0)
345 {
346 trace_GetRequestLine_failed();
347 return MI_FALSE;
348 }
349
|
350 mike 1.1 /* skip to end of line */
|
351 krisbash 1.3 for ( index = 1; (*line)[index] && index < handler->receivedSize; index++ )
|
352 mike 1.1 {
|
353 krisbash 1.3 if ((*line)[index-1] == '\r' && (*line)[index] == '\n')
|
354 mike 1.1 {
355 (*line) = (*line) + index + 1;
356 return MI_TRUE;
357 }
358 }
359
|
360 krisbash 1.3 trace_GetRequestLine_failed();
361
|
362 mike 1.1 return MI_FALSE;
363 }
364
365 static MI_Result _Sock_ReadAux(
366 Http_SR_SocketData* handler,
367 void* buf,
368 size_t buf_size,
369 size_t* sizeRead)
370 {
371 int res;
372
373 if (!handler->ssl)
|
374 krisbash 1.3 return Sock_Read(handler->handler.sock, buf, buf_size, sizeRead);
|
375 mike 1.1
|
376 krisbash 1.3 handler->handler.mask &= ~SELECTOR_WRITE;
377 handler->handler.mask |= SELECTOR_READ;
|
378 mike 1.1 handler->reverseOperations = MI_FALSE;
379
380 *sizeRead = 0;
381
382 if (handler->acceptDone)
383 {
384 res = SSL_read(handler->ssl, buf, buf_size);
385 }
386 else
387 {
388 res = SSL_accept(handler->ssl);
|
389 krisbash 1.3
|
390 mike 1.1 if ( res > 0 )
391 {
392 /* we are done with accpet */
393 handler->acceptDone = MI_TRUE;
394 return _Sock_ReadAux(handler,buf,buf_size,sizeRead);
395 }
396 /* perform regular error checking */
397 }
398
399 if ( res == 0 )
400 return MI_RESULT_OK; /* connection closed */
401
402 if ( res > 0 )
403 {
404 *sizeRead = res;
405 return MI_RESULT_OK; /* ok */
406 }
407
408 switch (SSL_get_error(handler->ssl, res))
409 {
410 case SSL_ERROR_WANT_WRITE:
411 mike 1.1 handler->reverseOperations = MI_TRUE; /* wait until write is allowed */
|
412 krisbash 1.3 handler->handler.mask |= SELECTOR_WRITE;
413 handler->handler.mask &= ~SELECTOR_READ;
414
|
415 mike 1.1 return MI_RESULT_WOULD_BLOCK;
416
417 case SSL_ERROR_WANT_READ:
418 return MI_RESULT_WOULD_BLOCK;
419
420 case SSL_ERROR_SYSCALL:
421 if (EAGAIN == errno ||
422 EWOULDBLOCK == errno ||
423 EINPROGRESS == errno)
424 return MI_RESULT_WOULD_BLOCK;
425
|
426 krisbash 1.3 trace_SSLRead_UnexpectedSysError(errno);
|
427 mike 1.1 break;
428
429 default:
430 {
431 /* print error */
432 unsigned long err = ERR_get_error();
433 while (err)
434 {
435 char err_txt[200];
436 ERR_error_string_n(err, err_txt, sizeof(err_txt));
437
|
438 krisbash 1.3 trace_SSLRead_Error((int)err, scs(err_txt));
|
439 mike 1.1 err = ERR_get_error();
440 }
441 }
442 break;
443 }
444 return MI_RESULT_FAILED;
445 }
446
447 static MI_Result _Sock_WriteAux(
448 Http_SR_SocketData* handler,
449 void* buf,
450 size_t buf_size,
451 size_t* sizeWritten)
452 {
453 int res;
454
455 if (!handler->ssl)
|
456 krisbash 1.3 return Sock_Write(handler->handler.sock, buf, buf_size, sizeWritten);
|
457 mike 1.1
458 /* Do not clear READ flag, since 'close' notification
459 delivered as READ event*/
|
460 krisbash 1.4 handler->handler.mask &= ~SELECTOR_READ;
|
461 krisbash 1.3 handler->handler.mask |= SELECTOR_WRITE;
|
462 mike 1.1 handler->reverseOperations = MI_FALSE;
463
464 *sizeWritten = 0;
465 res = SSL_write(handler->ssl, buf, buf_size);
466
467 if ( res == 0 )
468 return MI_RESULT_OK; /* connection closed */
469
470 if ( res > 0 )
471 {
472 *sizeWritten = res;
473 return MI_RESULT_OK; /* ok */
474 }
475
476 switch (SSL_get_error(handler->ssl, res))
477 {
478 case SSL_ERROR_WANT_WRITE:
479 return MI_RESULT_WOULD_BLOCK;
480
481 case SSL_ERROR_WANT_READ:
482 handler->reverseOperations = MI_TRUE; /* wait until write is allowed */
|
483 krisbash 1.3 handler->handler.mask |= SELECTOR_READ;
484 handler->handler.mask &= ~SELECTOR_WRITE;
|
485 mike 1.1 return MI_RESULT_WOULD_BLOCK;
486
487 case SSL_ERROR_SYSCALL:
488 if (EAGAIN == errno ||
489 EWOULDBLOCK == errno ||
490 EINPROGRESS == errno)
491 return MI_RESULT_WOULD_BLOCK;
492
|
493 krisbash 1.3 trace_SSLWrite_UnexpectedSysError(errno);
|
494 mike 1.1 break;
495
496 default:
497 break;
498 }
499 return MI_RESULT_FAILED;
500 }
501
502 static void _WriteTraceFile(PathID id, void* data, size_t size)
503 {
|
504 krisbash 1.3 #ifdef CONFIG_POSIX
|
505 mike 1.1 static pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
|
506 krisbash 1.3 #else
507 /* TODO: How to synchronize logging */
508 #endif
|
509 mike 1.1 const char* path;
|
510 krisbash 1.4
|
511 krisbash 1.3 if (!(path = OMI_GetPath(id)))
|
512 mike 1.1 return;
513
|
514 krisbash 1.3 #ifdef CONFIG_POSIX
|
515 mike 1.1 pthread_mutex_lock(&s_mutex);
|
516 krisbash 1.3 #else
517 /* TODO: How to synchronize logging */
518 #endif
|
519 mike 1.1 {
520 FILE* out = fopen(path, "a");
521
522 if (out)
|
523 krisbash 1.3 {
|
524 mike 1.1 fwrite(data, 1, size, out);
|
525 krisbash 1.3 fclose(out);
526 }
527 else
528 {
529 trace_CannotOpenHttptraceFile(path, errno);
530 }
|
531 mike 1.1 }
|
532 krisbash 1.3 #ifdef CONFIG_POSIX
|
533 mike 1.1 pthread_mutex_unlock(&s_mutex);
|
534 krisbash 1.3 #else
535 /* TODO: How to synchronize logging */
536 #endif
|
537 mike 1.1 }
538
539 INLINE MI_Result _Sock_Read(
540 Http_SR_SocketData* handler,
541 void* buf,
542 size_t buf_size,
543 size_t* sizeRead)
544 {
545 MI_Result r = _Sock_ReadAux(handler, buf, buf_size, sizeRead);
546
|
547 krisbash 1.3 if (FORCE_TRACING || (r == MI_RESULT_OK && handler->enableTracing))
|
548 mike 1.1 {
549 _WriteTraceFile(ID_HTTPRECVTRACEFILE, buf, *sizeRead);
550 }
551
552 return r;
553 }
554
555 INLINE MI_Result _Sock_Write(
556 Http_SR_SocketData* handler,
557 void* buf,
558 size_t buf_size,
559 size_t* sizeWritten)
560 {
561 MI_Result r = _Sock_WriteAux(handler, buf, buf_size, sizeWritten);
562
|
563 krisbash 1.3 if (FORCE_TRACING || (r == MI_RESULT_OK && handler->enableTracing))
|
564 mike 1.1 {
565 _WriteTraceFile(ID_HTTPSENDTRACEFILE, buf, *sizeWritten);
566 }
567
568 return r;
569 }
570
571 static Http_CallbackResult _ReadHeader(
572 Http_SR_SocketData* handler)
573 {
574 char* buf;
575 char* currentLine;
576 char* data;
577 size_t buf_size, received, index;
578 MI_Result r;
579 MI_Boolean fullHeaderReceived = MI_FALSE;
580
581 /* are we done with header? */
582 if (handler->recvingState == RECV_STATE_CONTENT)
583 return PRT_CONTINUE;
584
|
585 krisbash 1.3 buf = handler->recvBuffer + handler->receivedSize;
586 buf_size = handler->recvBufferSize - handler->receivedSize;
|
587 mike 1.1 received = 0;
588
589 r = _Sock_Read(handler, buf, buf_size, &received);
590
591 if ( r == MI_RESULT_OK && 0 == received )
592 return PRT_RETURN_FALSE; /* conection closed */
593
594 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
595 return PRT_RETURN_FALSE;
596
597 if (!received)
598 return PRT_RETURN_TRUE;
599
|
600 krisbash 1.3 handler->receivedSize += received;
|
601 mike 1.1
602 /* did we get full header? */
603 buf = handler->recvBuffer;
|
604 krisbash 1.3 for ( index = 3; index < handler->receivedSize; index++ )
|
605 mike 1.1 {
606 if (buf[index-3] == '\r' && buf[index-1] == '\r' &&
607 buf[index-2] == '\n' && buf[index] == '\n' )
608 {
609 fullHeaderReceived = MI_TRUE;
610 break;
611 }
612 }
613
614 if (!fullHeaderReceived )
615 {
|
616 krisbash 1.3 if ( handler->receivedSize < handler->recvBufferSize )
|
617 mike 1.1 return PRT_RETURN_TRUE; /* continue reading */
618
619 if ( handler->recvBufferSize < MAX_HEADER_SIZE )
620 {
|
621 krisbash 1.3 buf = PAL_Realloc(handler->recvBuffer, handler->recvBufferSize * 2);
|
622 mike 1.1
623 if (!buf)
624 return PRT_RETURN_FALSE;
625
626 handler->recvBufferSize *= 2;
627 handler->recvBuffer = buf;
628 return _ReadHeader(handler);
629 }
630 else
631 {
632 /* http header is too big - drop connection */
|
633 krisbash 1.3 trace_HttpHeaderIsTooBig();
|
634 mike 1.1 return PRT_RETURN_FALSE;
635 }
636 }
637
638 /* consume data */
639 currentLine = buf;
640 data = buf + index + 1; /* pointer to data in case we got some */
641
642 if (!_getRequestLine(handler, ¤tLine))
643 return PRT_RETURN_FALSE;
644
645
646 while ((data-currentLine) > 3)
647 {
648 if (!_getHeaderField(handler, ¤tLine))
649 return PRT_RETURN_FALSE;
650
651 }
652
|
653 krisbash 1.4 size_t allocSize = 0;
654 if (SizeTAdd(sizeof(Page), handler->recvHeaders.contentLength, &allocSize) == S_OK &&
655 SizeTAdd(allocSize, 1, &allocSize) == S_OK)
656 {
657 /* Allocate zero-terminated buffer */
658 handler->recvPage = (Page*)PAL_Malloc(allocSize);
659 }
660 else
661 {
662 // Overflow
663 return PRT_RETURN_FALSE;
664 }
|
665 mike 1.1
666 if (!handler->recvPage)
667 return PRT_RETURN_FALSE;
668
669 ((char*)(handler->recvPage + 1))[handler->recvHeaders.contentLength] = 0;
670
671 handler->recvPage->u.s.size = (unsigned int)handler->recvHeaders.contentLength;
672 handler->recvPage->u.s.next = 0;
673
|
674 krisbash 1.3 handler->receivedSize -= index + 1;
|
675 mike 1.1
|
676 krisbash 1.4 /* Verify that we have not more than 'content-length' bytes in buffer left
|
677 mike 1.1 If we hvae more, assuming http client is invalid and drop connection */
|
678 krisbash 1.3 if (handler->receivedSize > handler->recvHeaders.contentLength)
|
679 mike 1.1 {
|
680 krisbash 1.3 trace_HttpPayloadIsBiggerThanContentLength();
|
681 mike 1.1 return PRT_RETURN_FALSE;
682 }
683
|
684 krisbash 1.3 memcpy( handler->recvPage + 1, data, handler->receivedSize );
|
685 mike 1.1 handler->recvingState = RECV_STATE_CONTENT;
686
687 return PRT_CONTINUE;
688 }
689
690 static Http_CallbackResult _ReadData(
691 Http_SR_SocketData* handler)
692 {
693 char* buf;
694 size_t buf_size, received;
695 MI_Result r;
|
696 krisbash 1.3 HttpRequestMsg* msg;
|
697 mike 1.1
698 /* are we in the right state? */
699 if (handler->recvingState != RECV_STATE_CONTENT)
700 return PRT_RETURN_FALSE;
701
|
702 krisbash 1.3 buf = ((char*)(handler->recvPage + 1)) + handler->receivedSize;
703 buf_size = handler->recvHeaders.contentLength - handler->receivedSize;
|
704 mike 1.1 received = 0;
705
706 if (buf_size)
707 {
708 r = _Sock_Read(handler, buf, buf_size, &received);
709
710 if ( r == MI_RESULT_OK && 0 == received )
711 return PRT_RETURN_FALSE; /* conection closed */
712
713 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
714 return PRT_RETURN_FALSE;
715
|
716 krisbash 1.3 handler->receivedSize += received;
|
717 mike 1.1 }
718
719 /* did we get all data? */
720
|
721 krisbash 1.3 if ( handler->receivedSize != handler->recvHeaders.contentLength )
|
722 mike 1.1 return PRT_RETURN_TRUE;
|
723 krisbash 1.4
|
724 krisbash 1.3 msg = HttpRequestMsg_New(handler->recvPage, &handler->recvHeaders);
725
726 if( NULL == msg )
727 {
728 trace_HTTP_RequestAllocFailed( handler );
729
730 if (handler->recvPage)
731 {
732 PAL_Free(handler->recvPage);
733 handler->recvPage = NULL; /* clearing this out so that caller does not double-free it */
734 }
735
736 return PRT_RETURN_FALSE;
737 }
|
738 krisbash 1.4
|
739 mike 1.1 handler->requestIsBeingProcessed = MI_TRUE;
740
|
741 krisbash 1.3 // the page will be owned by receiver of this message
742 DEBUG_ASSERT( NULL == handler->request );
743 handler->request = msg;
744 Strand_ScheduleAux( &handler->strand, HTTPSOCKET_STRANDAUX_NEWREQUEST );
|
745 mike 1.1
746 handler->recvPage = 0;
|
747 krisbash 1.3 handler->receivedSize = 0;
|
748 mike 1.1 memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
749 handler->recvingState = RECV_STATE_HEADER;
750 return PRT_CONTINUE;
751 }
752
753 static MI_Boolean _RequestCallbackRead(
754 Http_SR_SocketData* handler)
755 {
756 switch (_ReadHeader(handler))
757 {
758 case PRT_CONTINUE: break;
759 case PRT_RETURN_TRUE: return MI_TRUE;
760 case PRT_RETURN_FALSE: return MI_FALSE;
761 }
762
763 switch (_ReadData(handler))
764 {
765 case PRT_CONTINUE: break;
766 case PRT_RETURN_TRUE: return MI_TRUE;
767 case PRT_RETURN_FALSE: return MI_FALSE;
768 }
769 mike 1.1 return MI_TRUE;
770 }
771
772 /* length of longest description - has to be updated if descriptions are updated */
773 #define HTTP_LONGEST_ERROR_DESCRIPTION 50
774 static const char* _GetHttpErrorCodeDescription(
775 int httpErrorCode )
776 {
777 switch (httpErrorCode)
778 {
779 case 200:
780 return "OK";
781
782 case 400:
783 return "Bad Request";
784
785 case 401:
786 return "Unauthorized";
787
788 case 500:
789 return "Internal Server Error";
790 mike 1.1 }
791 return "Error";
792 }
793
|
794 krisbash 1.4 /*
795 * Common clean up function that reverts the changes made when preparing
|
796 krisbash 1.3 * the strand for a write.
797 */
798 static void _ResetWriteState(
799 Http_SR_SocketData* socketData )
800 {
801 if (socketData->sendPage)
802 {
803 PAL_Free(socketData->sendPage);
804 socketData->sendPage = 0;
805 }
806 socketData->httpErrorCode = 0;
807 socketData->sentSize = 0;
808 socketData->sendingState = RECV_STATE_HEADER;
809 socketData->handler.mask &= ~SELECTOR_WRITE;
810 socketData->handler.mask |= SELECTOR_READ;
811 }
812
|
813 mike 1.1 static Http_CallbackResult _WriteHeader(
814 Http_SR_SocketData* handler)
815 {
816 #define RESPONSE_HEADER_FMT \
817 "HTTP/1.1 %d %s\r\n" \
818 "Content-Length: %d\r\n"\
819 "Connection: Keep-Alive\r\n"\
820 "Content-Type: application/soap+xml;charset=UTF-8\r\n"\
821 "\r\n"
822
|
823 krisbash 1.3 #define RESPONSE_HEADER_NO_AUTH_FMT "HTTP/1.1 %d %s\r\n\r\n"
824
825 #define RESPONSE_HEADER_401_ERROR_FMT \
826 "HTTP/1.1 %d %s \r\n" \
827 HTTP_WWWAUTHENTICATE_BASIC\
828 "\r\n"\
829 "Content-Length: 0\r\n"\
830 "\r\n"
831
|
832 mike 1.1 /* "SOAPAction: http://schemas.xmlsoap.org/ws/2004/08/addressing/fault\r\n"\ */
833
|
834 krisbash 1.4 char currentLine[sizeof(RESPONSE_HEADER_FMT) +
835 10 /* content length */ +
836 10 /*error code*/ +
|
837 mike 1.1 HTTP_LONGEST_ERROR_DESCRIPTION /* code descirpiton */ ];
838 char* buf;
839 size_t buf_size, sent;
840 MI_Result r;
841
842 /* Do we have any data to send? */
843 if (!handler->sendPage && 0 == handler->httpErrorCode)
844 return PRT_RETURN_TRUE;
845
846 /* are we done with header? */
847 if (handler->sendingState == RECV_STATE_CONTENT)
848 return PRT_CONTINUE;
849
850 if (handler->sendPage)
851 {
852 buf_size = (size_t)Snprintf(
853 currentLine,
854 sizeof(currentLine),
|
855 krisbash 1.4 RESPONSE_HEADER_FMT,
856 (int)handler->httpErrorCode,
|
857 mike 1.1 _GetHttpErrorCodeDescription(handler->httpErrorCode),
858 (int)handler->sendPage->u.s.size );
859 }
860 else
861 {
|
862 krisbash 1.3 int httpErrorCode = (int)handler->httpErrorCode;
863 /*
|
864 krisbash 1.4 Check the error code and in case it is "HTTP_ERROR_CODE_UNAUTHORIZED" (401), then we need to send the
865 "WWW-Authenticate" header field. Since right now we only support "Basic" auth so the header will contains
|
866 krisbash 1.3 "WWW-Authenticate: Basic realm=\"WSMAN\".
867 */
868 char * response = (httpErrorCode == HTTP_ERROR_CODE_UNAUTHORIZED) ? RESPONSE_HEADER_401_ERROR_FMT : RESPONSE_HEADER_NO_AUTH_FMT;
|
869 krisbash 1.4
|
870 mike 1.1 buf_size = (size_t)Snprintf(
871 currentLine,
872 sizeof(currentLine),
|
873 krisbash 1.4 response,
|
874 krisbash 1.3 httpErrorCode,
|
875 mike 1.1 _GetHttpErrorCodeDescription(handler->httpErrorCode));
876 }
877
878 buf = currentLine + handler->sentSize;
879
880 sent = 0;
881
882 r = _Sock_Write(handler, buf, buf_size - handler->sentSize, &sent);
883
884 if ( r == MI_RESULT_OK && 0 == sent )
885 return PRT_RETURN_FALSE; /* conection closed */
886
887 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
888 return PRT_RETURN_FALSE;
889
890 if (!sent)
891 return PRT_RETURN_TRUE;
892
893 handler->sentSize += sent;
894
895 if (handler->sentSize < buf_size)
896 mike 1.1 return PRT_RETURN_TRUE;
897
898 handler->sentSize = 0;
899 handler->sendingState = RECV_STATE_CONTENT;
900 return PRT_CONTINUE;
901 }
902
903 static Http_CallbackResult _WriteData(
904 Http_SR_SocketData* handler)
905 {
906 char* buf;
907 size_t buf_size, sent;
908 MI_Result r;
909
910 /* are we in the right state? */
911 if (handler->sendingState != RECV_STATE_CONTENT)
912 return PRT_RETURN_FALSE;
913
914 if (!handler->sendPage)
915 { /* no content*/
|
916 krisbash 1.3 _ResetWriteState( handler );
|
917 mike 1.1 return PRT_CONTINUE;
918 }
919
920 buf = ((char*)(handler->sendPage + 1)) + handler->sentSize;
921 buf_size = handler->sendPage->u.s.size - handler->sentSize;
922 sent = 0;
923
924 r = _Sock_Write(handler, buf, buf_size, &sent);
925
926 if ( r == MI_RESULT_OK && 0 == sent )
927 return PRT_RETURN_FALSE; /* conection closed */
928
929 if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
930 return PRT_RETURN_FALSE;
931
932 handler->sentSize += sent;
933
934 /* did we get all data? */
935
936 if ( handler->sentSize != handler->sendPage->u.s.size )
937 return PRT_RETURN_TRUE;
|
938 krisbash 1.4
|
939 krisbash 1.3 _ResetWriteState( handler );
|
940 mike 1.1
941 return PRT_CONTINUE;
942 }
943
944 static MI_Boolean _RequestCallbackWrite(
945 Http_SR_SocketData* handler)
946 {
947 switch (_WriteHeader(handler))
948 {
949 case PRT_CONTINUE: break;
950 case PRT_RETURN_TRUE: return MI_TRUE;
|
951 krisbash 1.4 case PRT_RETURN_FALSE:
|
952 krisbash 1.3 _ResetWriteState( handler );
953 return MI_FALSE;
|
954 mike 1.1 }
955
956 switch (_WriteData(handler))
957 {
958 case PRT_CONTINUE: break;
959 case PRT_RETURN_TRUE: return MI_TRUE;
|
960 krisbash 1.4 case PRT_RETURN_FALSE:
|
961 krisbash 1.3 _ResetWriteState( handler );
962 return MI_FALSE;
|
963 mike 1.1 }
964 return MI_TRUE;
965 }
966
967 static MI_Boolean _RequestCallback(
968 Selector* sel,
969 Handler* handlerIn,
|
970 krisbash 1.4 MI_Uint32 mask,
|
971 mike 1.1 MI_Uint64 currentTimeUsec)
972 {
|
973 krisbash 1.3 Http_SR_SocketData* handler = FromOffset( Http_SR_SocketData, handler, handlerIn );
|
974 mike 1.1 sel=sel;
975
976 if ( ((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||
977 ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations) )
978 {
979 if (!_RequestCallbackRead(handler))
|
980 krisbash 1.3 {
981 trace_RequestCallbackRead_Failed(handler);
|
982 mike 1.1 return MI_FALSE;
|
983 krisbash 1.3 }
|
984 mike 1.1 }
985
986 if ( ((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||
987 ((mask & SELECTOR_READ) != 0 && handler->reverseOperations) )
988 {
989 if (!_RequestCallbackWrite(handler))
|
990 krisbash 1.3 {
991 trace_RequestCallbackWrite_Failed();
|
992 mike 1.1 return MI_FALSE;
|
993 krisbash 1.3 }
|
994 mike 1.1 }
|
995 krisbash 1.4
|
996 mike 1.1 /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */
997 if (mask & (SELECTOR_READ | SELECTOR_WRITE))
998 {
|
999 krisbash 1.3 Http* self = (Http*)handler->handler.data;
|
1000 mike 1.1
1001 if (handler->requestIsBeingProcessed)
1002 {
1003 /* since request is processed by server, disable timeout for this period */
|
1004 krisbash 1.3 handler->handler.fireTimeoutAt = TIME_NEVER;
|
1005 mike 1.1 }
1006 else
1007 {
1008 /* Use configuration timeout */
|
1009 krisbash 1.3 handler->handler.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;
|
1010 mike 1.1 }
1011 }
1012
1013 /* Close conenction by timeout */
1014 if (mask & SELECTOR_TIMEOUT)
|
1015 krisbash 1.3 {
1016 trace_ConnectionClosed_Timeout();
|
1017 mike 1.1 return MI_FALSE;
|
1018 krisbash 1.3 }
|
1019 mike 1.1
1020 if ((mask & SELECTOR_REMOVE) != 0 ||
1021 (mask & SELECTOR_DESTROY) != 0)
1022 {
1023 if (handler->ssl)
1024 SSL_free(handler->ssl);
1025
|
1026 krisbash 1.3 trace_SocketClose_REMOVEDESTROY();
|
1027 mike 1.1
|
1028 krisbash 1.3 Sock_Close(handler->handler.sock);
1029
1030 // Free the savedSendMsg and ACK it to prevent leaks when a non-io thread
1031 // writes to the socket, but it cannot be read because of an error or a
1032 // ECONNRESET.
1033 if (handler->savedSendMsg)
1034 {
1035 Message_Release(handler->savedSendMsg);
1036 handler->savedSendMsg = NULL;
1037 DEBUG_ASSERT(handler->strand.info.otherAckPending);
1038 Strand_ScheduleAck( &handler->strand );
1039 }
|
1040 mike 1.1
1041 if (handler->recvPage)
|
1042 krisbash 1.3 PAL_Free(handler->recvPage);
|
1043 mike 1.1
1044 if (handler->sendPage)
|
1045 krisbash 1.3 PAL_Free(handler->sendPage);
1046
1047 PAL_Free(handler->recvBuffer);
1048 // handler deleted on its own strand
|
1049 mike 1.1
|
1050 krisbash 1.4 // notify next stack layer
|
1051 krisbash 1.3 // (only after internal data has been deleted as this may delete the object)
1052 Strand_ScheduleClose( &handler->strand );
|
1053 mike 1.1 }
1054
1055 return MI_TRUE;
1056 }
1057
|
1058 krisbash 1.3 /*
1059 **==============================================================================
1060 */
1061
1062 static void _SendIN_IO_thread_HttpSocket(void* self_, Message* message)
1063 {
1064 Http_SR_SocketData* sendSock = (Http_SR_SocketData*)self_;
1065 HttpResponseMsg * response = (HttpResponseMsg *)message;
1066
1067 DEBUG_ASSERT( sendSock );
1068 DEBUG_ASSERT( HttpResponseMsgTag == message->tag );
1069
1070 /* validate handler */
1071
1072 if (MI_RESULT_OK != Selector_ContainsHandler(
1073 sendSock->http->selector, &sendSock->handler ) )
1074 {
1075 trace_SendIN_IO_thread_HttpSocket_InvalidHandler(sendSock);
1076 return;
1077 }
1078
1079 krisbash 1.3 sendSock->requestIsBeingProcessed = MI_FALSE;
1080
1081 sendSock->handler.mask |= SELECTOR_WRITE;
1082 sendSock->handler.mask &= ~SELECTOR_READ;
1083
1084 // Now we take ownership of the page
1085 sendSock->sendPage = response->page;
1086 response->page = NULL;
1087 sendSock->httpErrorCode = response->httpErrorCode;
1088
1089 sendSock->sentSize = 0;
1090 sendSock->sendingState = RECV_STATE_HEADER;
1091
1092 // Done after response->page is NULL'd to prevent early release
1093 // of that memory in the message's destructor
1094 DEBUG_ASSERT( sendSock->savedSendMsg );
1095 Message_Release(sendSock->savedSendMsg);
1096 sendSock->savedSendMsg = NULL;
1097
1098 if( !_RequestCallbackWrite(sendSock) )
1099 {
1100 krisbash 1.3 trace_SendIN_IO_thread_HttpSocket_WriteFailed();
1101 }
1102
1103 Strand_ScheduleAck( &sendSock->strand );
1104 }
1105
1106 void _HttpSocket_Post( _In_ Strand* self_, _In_ Message* msg)
1107 {
1108 Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
1109 DEBUG_ASSERT( NULL != self_ );
1110 trace_HttpSocketPosting(&self->strand.info.interaction, self->strand.info.interaction.other);
1111
1112 // Preserve the message in case there is an error while writing it to the socket during
1113 // non-IO thread calls to Selector_CallInIOThread.
1114 // A ref to the message is held until the message is ACK'd.
1115 DEBUG_ASSERT( NULL == self->savedSendMsg );
1116 Message_AddRef(msg);
1117 self->savedSendMsg = msg;
|
1118 krisbash 1.4
|
1119 krisbash 1.3 if( MI_RESULT_OK != Selector_CallInIOThread(
1120 self->http->selector, _SendIN_IO_thread_HttpSocket, self, msg ) )
1121 {
1122 // We also need to release the page (if any)
1123 HttpResponseMsg * response = (HttpResponseMsg *)msg;
1124 DEBUG_ASSERT( HttpResponseMsgTag == msg->tag );
|
1125 krisbash 1.4
|
1126 krisbash 1.3 trace_HttpSocket_CannotPostMessage( self, msg, &self->strand.info.interaction, self->strand.info.interaction.other );
1127
1128 HttpResponseMsg_Release( response ); // same message as savedSendMsg
1129 self->savedSendMsg = NULL;
1130 Strand_ScheduleAck( &self->strand );
1131 }
1132 }
1133
1134 void _HttpSocket_PostControl( _In_ Strand* self, _In_ Message* msg)
1135 {
1136 DEBUG_ASSERT( MI_FALSE ); // not used yet
1137 }
1138
1139 void _HttpSocket_Ack( _In_ Strand* self)
1140 {
1141 trace_HttpSocketAck( &self->info.interaction, self->info.interaction.other );
1142 // No need to do anything for now
1143 }
1144
1145 void _HttpSocket_Cancel( _In_ Strand* self)
1146 {
1147 krisbash 1.3 // no need to do anything here (upper layer should send proper error response)
1148 }
1149
1150 void _HttpSocket_Finish( _In_ Strand* self_)
1151 {
1152 Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
1153 DEBUG_ASSERT( NULL != self_ );
|
1154 krisbash 1.4
|
1155 krisbash 1.3 trace_HttpSocketFinish( self_ );
1156 Strand_Delete( &self->strand );
1157 }
1158
1159 // HTTPSOCKET_STRANDAUX_NEWREQUEST
1160 void _HttpSocket_Aux_NewRequest( _In_ Strand* self_)
1161 {
1162 Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
1163 HttpRequestMsg* msg;
1164
1165 DEBUG_ASSERT( NULL != self_ );
1166 msg = self->request;
1167 DEBUG_ASSERT( NULL != msg );
|
1168 krisbash 1.4
|
1169 krisbash 1.3 trace_HttpSocketAuxNewRequest( self, msg );
1170 self->request = NULL;
1171
1172 if( !self_->info.thisClosedOther )
1173 {
|
1174 krisbash 1.4 // Leave the strand for the case where the new request provider
|
1175 krisbash 1.3 // is in-proc and takes over the thread
1176 Strand_PostAndLeaveStrand( &self->strand, &msg->base );
1177 }
1178
1179 HttpRequestMsg_Release( msg );
1180 }
1181
1182 /*
1183 Object that implements the HTTP protocol endpoint on a TCP Socket.
1184 Usually connects to WSMAN interaction object.
1185
1186 Behaviour:
1187 - Post tries to schedule the operation on the IO thread (thru selector)
|
1188 krisbash 1.4 if that fails it sends the Ack immediately. Note that the response message
|
1189 krisbash 1.3 is delivered from WSMAN inside a HttpResponseMsg
1190 - Post control is not implemented
1191 - Both Cancel, Close and Ack do nothing (in case of cancelation upper layer should
1192 send an actual response)
|
1193 krisbash 1.4 - Shutdown:
|
1194 krisbash 1.3 Once the connection is closed by the client that is notified to _RequestCallback
1195 which calls Strand_ScheduleClose on component to the right.
|
1196 krisbash 1.4 From there normal Strand logic applies: once the upper layer
|
1197 krisbash 1.3 also closes the interaction the object is deleted.
1198
1199 Unique features and special Behavour:
1200 - When a complete message has been read instead of scheduling a post
|
1201 krisbash 1.4 the auxiliary function HTTPSOCKET_STRANDAUX_NEWREQUEST is
1202 scheduled instead. That function takes care of posting using
1203 Strand_PostAndLeaveStrand (which avoids holding the strand in case the thread
|
1204 krisbash 1.3 is going to be hijacked by the provider in the processing of that post).
1205 */
|
1206 krisbash 1.4 static StrandFT _HttpSocket_FT = {
1207 _HttpSocket_Post,
1208 _HttpSocket_PostControl,
1209 _HttpSocket_Ack,
1210 _HttpSocket_Cancel,
|
1211 krisbash 1.3 NULL,
1212 _HttpSocket_Finish,
1213 NULL,
1214 _HttpSocket_Aux_NewRequest,
1215 NULL,
1216 NULL,
1217 NULL,
1218 NULL };
1219
1220 /*
1221 **==============================================================================
1222 */
|
1223 krisbash 1.4
|
1224 mike 1.1 static MI_Boolean _ListenerCallback(
1225 Selector* sel,
1226 Handler* handler_,
|
1227 krisbash 1.4 MI_Uint32 mask,
|
1228 mike 1.1 MI_Uint64 currentTimeUsec)
1229 {
1230 Http_Listener_SocketData* handler = (Http_Listener_SocketData*)handler_;
1231 Http* self = (Http*)handler->base.data;
1232 MI_Result r;
1233 Sock s;
1234 Addr addr;
1235 Http_SR_SocketData* h;
1236
1237 sel=sel;
1238 mask=mask;
1239 currentTimeUsec = currentTimeUsec;
1240
1241 if (mask & SELECTOR_READ)
1242 {
|
1243 krisbash 1.4 /* Accept the incoming connection */
1244 r = Sock_Accept(handler->base.sock, &s, &addr);
1245
1246 if (MI_RESULT_WOULD_BLOCK == r)
1247 return MI_TRUE;
1248
|
1249 mike 1.1
|
1250 krisbash 1.4 if (r != MI_RESULT_OK)
|
1251 mike 1.1 {
|
1252 krisbash 1.4 trace_SockAccept_Failed(Sock_GetLastError());
1253 return MI_TRUE;
1254 }
|
1255 mike 1.1
|
1256 krisbash 1.4 r = Sock_SetBlocking(s, MI_FALSE);
1257 if (r != MI_RESULT_OK)
1258 {
1259 trace_SockSetBlocking_Failed();
1260 Sock_Close(s);
1261 return MI_TRUE;
1262 }
1263
1264 /* Create handler */
1265 h = (Http_SR_SocketData*)Strand_New( STRAND_DEBUG( HttpSocket ) &_HttpSocket_FT, sizeof(Http_SR_SocketData), STRAND_FLAG_ENTERSTRAND, NULL );
|
1266 mike 1.1
|
1267 krisbash 1.4 if (!h)
1268 {
1269 trace_SocketClose_Http_SR_SocketDataAllocFailed();
1270 Sock_Close(s);
1271 return MI_TRUE;
1272 }
|
1273 mike 1.1
|
1274 krisbash 1.4 h->http = self;
1275 h->recvBufferSize = INITIAL_BUFFER_SIZE;
1276 h->recvBuffer = (char*)PAL_Calloc(1, h->recvBufferSize);
1277 if (!h->recvBuffer)
1278 {
1279 Strand_Delete(&h->strand);
1280 trace_SocketClose_recvBuffer_AllocFailed();
1281 Sock_Close(s);
1282 return MI_TRUE;
1283 }
|
1284 mike 1.1
|
1285 krisbash 1.4 h->handler.sock = s;
1286 h->handler.mask = SELECTOR_READ | SELECTOR_EXCEPTION;
1287 h->handler.callback = _RequestCallback;
1288 h->handler.data = self;
1289 h->handler.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;
1290 h->enableTracing = self->options.enableTracing;
|
1291 mike 1.1
|
1292 krisbash 1.4 /* ssl support */
1293 if (handler->secure)
1294 {
1295 h->ssl = SSL_new(self->sslContext);
|
1296 mike 1.1
|
1297 krisbash 1.4 if (!h->ssl)
|
1298 mike 1.1 {
|
1299 krisbash 1.4 trace_SSLNew_Failed();
1300 Strand_Delete(&h->strand);
|
1301 mike 1.1 Sock_Close(s);
1302 return MI_TRUE;
1303 }
1304
|
1305 krisbash 1.4 if (!(SSL_set_fd(h->ssl, s) ))
|
1306 mike 1.1 {
|
1307 krisbash 1.4 trace_SSL_setfd_Failed();
1308 SSL_free(h->ssl);
|
1309 krisbash 1.3 Strand_Delete(&h->strand);
|
1310 mike 1.1 Sock_Close(s);
1311 return MI_TRUE;
1312 }
|
1313 krisbash 1.4 }
|
1314 mike 1.1
|
1315 krisbash 1.4 /* Watch for read events on the incoming connection */
1316 r = Selector_AddHandler(self->selector, &h->handler);
|
1317 mike 1.1
|
1318 krisbash 1.4 if (r != MI_RESULT_OK)
1319 {
1320 trace_SelectorAddHandler_Failed();
|
1321 mike 1.1 if (handler->secure)
|
1322 krisbash 1.4 SSL_free(h->ssl);
1323 Strand_Delete(&h->strand);
1324 Sock_Close(s);
1325 return MI_TRUE;
1326 }
|
1327 mike 1.1
|
1328 krisbash 1.4 // notify next stack layer about new connection
1329 // (open the interaction)
1330 Strand_Open(
1331 &h->strand,
1332 self->callbackOnNewConnection,
1333 self->callbackData,
1334 NULL,
1335 MI_TRUE );
|
1336 mike 1.1 }
1337
1338 if ((mask & SELECTOR_REMOVE) != 0 ||
1339 (mask & SELECTOR_DESTROY) != 0)
1340 {
|
1341 krisbash 1.3 trace_SocketClose_REMOVEDESTROY();
|
1342 mike 1.1 Sock_Close(handler->base.sock);
|
1343 krisbash 1.3 PAL_Free(handler);
|
1344 mike 1.1 }
1345
1346 return MI_TRUE;
1347 }
1348
1349 static MI_Result _New_Http(
|
1350 krisbash 1.3 _Out_ Http** selfOut,
1351 _In_ Selector* selector, /*optional, maybe NULL*/
1352 _In_ OpenCallback callbackOnNewConnection,
1353 _In_opt_ void* callbackData)
|
1354 mike 1.1 {
1355 Http* self;
1356
1357 /* Check parameters */
1358 if (!selfOut)
1359 return MI_RESULT_INVALID_PARAMETER;
1360
1361 /* Clear output parameter */
1362 *selfOut = NULL;
1363
1364 /* Allocate structure */
1365 {
|
1366 krisbash 1.3 self = (Http*)PAL_Calloc(1, sizeof(Http));
|
1367 mike 1.1
1368 if (!self)
1369 return MI_RESULT_FAILED;
1370 }
1371
1372 if (selector)
1373 { /* attach the exisiting selector */
1374 self->selector = selector;
1375 self->internalSelectorUsed = MI_FALSE;
1376 }
1377 else
1378 { /* creaet a new selector */
1379 /* Initialize the network */
1380 Sock_Start();
1381
1382 /* Initialize the selector */
1383 if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)
1384 {
|
1385 krisbash 1.3 PAL_Free(self);
|
1386 mike 1.1 return MI_RESULT_FAILED;
1387 }
1388 self->selector = &self->internalSelector;
1389 self->internalSelectorUsed = MI_TRUE;
1390 }
1391
1392 /* Save the callback and callbackData */
1393 self->callbackOnNewConnection = callbackOnNewConnection;
1394 self->callbackData = callbackData;
1395
1396 /* Set the magic number */
1397 self->magic = _MAGIC;
1398
1399 /* Set output parameter */
1400 *selfOut = self;
1401 return MI_RESULT_OK;
1402 }
1403
1404 #ifdef CONFIG_POSIX
1405 static MI_Boolean _verifyPrivateKey(
|
1406 krisbash 1.4 SSL_CTX *ctx,
|
1407 mike 1.1 const char* keyPath)
1408 {
1409 // Open the private key file.
1410
1411 FILE* is = fopen(keyPath, "r");
1412
1413 if (!is)
1414 {
|
1415 krisbash 1.3 trace_SSL_FailedToOpenPrivateKeyFile(scs(keyPath));
|
1416 mike 1.1 return MI_FALSE;
1417 }
1418
1419 // Read the private key from the input stream.
1420
1421 EVP_PKEY* pkey;
1422 pkey = PEM_read_PrivateKey(is, NULL, NULL, NULL);
1423
1424 if (!pkey)
1425 {
|
1426 krisbash 1.3 trace_SSL_FailedToCreatePrivateKey();
|
1427 mike 1.1 return MI_FALSE;
1428 }
1429
1430 /* Close the input stream. */
1431
1432 fclose(is);
1433
1434 /* Associate the new private key with the SSL context object. */
1435
1436 if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0)
1437 {
1438 EVP_PKEY_free(pkey);
|
1439 krisbash 1.3 trace_SSL_NoPrivateKeyFound(scs(keyPath));
|
1440 mike 1.1 return MI_FALSE;
1441 }
1442
1443 EVP_PKEY_free(pkey);
1444
1445 /* Check private key for validity. */
1446
1447 if (!SSL_CTX_check_private_key(ctx))
1448 {
|
1449 krisbash 1.3 trace_SSL_PrivateAndPublicKeyDonotMatch();
|
1450 mike 1.1 return MI_FALSE;
1451 }
1452
1453 return MI_TRUE;
1454 }
1455
|
1456 krisbash 1.3 static MI_Result _CreateSSLContext(Http* self, const char* sslCipherSuite, Server_SSL_Options sslOptions)
|
1457 mike 1.1 {
|
1458 krisbash 1.3 SSL_CTX* sslContext = 0;
1459 long options = 0;
|
1460 mike 1.1
1461 sslContext = SSL_CTX_new(SSLv23_method());
1462
1463 if (!sslContext)
1464 {
|
1465 krisbash 1.3 trace_SSL_CannotCreateContext();
|
1466 mike 1.1 return MI_RESULT_FAILED;
1467 }
|
1468 krisbash 1.3
1469 if (sslCipherSuite != NULL)
1470 {
1471 // Set the cipher list to the user specified cipher list.
1472 if (SSL_CTX_set_cipher_list(sslContext, sslCipherSuite) == 0)
1473 {
1474 trace_SSL_BadCipherList(scs(sslCipherSuite));
1475 return MI_RESULT_FAILED;
1476 }
1477 }
1478
1479 // Disable SSL_v2 and/or SSL_v3 if requested
1480 if ( sslOptions & DISABLE_SSL_V2 )
1481 {
1482 options |= SSL_OP_NO_SSLv2;
1483 }
1484 if ( sslOptions & DISABLE_SSL_V3 )
1485 {
1486 options |= SSL_OP_NO_SSLv3;
1487 }
1488 if ( SSL_CTX_set_options(sslContext, options) == 0 )
1489 krisbash 1.3 {
1490 trace_SSL_CannotSetOptions( options );
1491 return MI_RESULT_FAILED;
1492 }
1493
|
1494 mike 1.1 SSL_CTX_set_quiet_shutdown(sslContext, 1);
1495 SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
1496 SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);
1497 SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
1498
1499 /* Check if there is a certificate file (file containing server
1500 ** certificate) specified. If specified, validate and load the
1501 ** certificate.
1502 */
1503 {
|
1504 krisbash 1.3 char errorBuf[256];
1505
|
1506 mike 1.1 /* load the specified server certificates */
|
1507 krisbash 1.3 trace_SSL_LoadingServerCert(scs(OMI_GetPath(ID_PEMFILE)));
|
1508 mike 1.1
1509 if (SSL_CTX_use_certificate_file(sslContext,
|
1510 krisbash 1.3 OMI_GetPath(ID_PEMFILE), SSL_FILETYPE_PEM) <=0)
|
1511 mike 1.1 {
|
1512 krisbash 1.3 trace_SSL_NoServerCertFound(OMI_GetPath(ID_PEMFILE), GetSslErrorString(errorBuf, 256));
|
1513 mike 1.1 SSL_CTX_free(sslContext);
1514 return MI_RESULT_FAILED;
1515 }
1516 }
1517
1518 /*
1519 ** Check if there is a key file (file containing server
1520 ** private key) specified and the key was not already loaded.
1521 ** If specified, validate and load the key.
1522 */
1523 {
|
1524 krisbash 1.3 char errorBuf[256];
1525
|
1526 mike 1.1 /* load the specified server certificates */
|
1527 krisbash 1.3 trace_SSL_LoadingCertPrivateKey(scs(OMI_GetPath(ID_KEYFILE)));
|
1528 mike 1.1
|
1529 krisbash 1.3 /* load given private key and check for validity
1530 */
1531 if (!_verifyPrivateKey(sslContext, OMI_GetPath(ID_KEYFILE)))
1532 {
1533 trace_SSL_NoServerCertFound(scs(OMI_GetPath(ID_KEYFILE)), GetSslErrorString(errorBuf, sizeof errorBuf));
|
1534 mike 1.1 SSL_CTX_free(sslContext);
1535 return MI_RESULT_FAILED;
1536 }
1537 }
1538
1539 self->sslContext = sslContext;
1540 return MI_RESULT_OK;
1541 }
1542 #endif
1543
1544 static MI_Result _CreateAddListenerSocket(
1545 Http* self,
1546 unsigned short port,
1547 MI_Boolean secure
1548 )
1549 {
1550 Addr addr;
1551 Sock listener;
1552 MI_Result r;
1553
1554 /* Create listener socket */
1555 mike 1.1 {
1556 Addr_InitAny(&addr, port);
1557 r = Sock_CreateListener(&listener, &addr);
1558
1559 if (r != MI_RESULT_OK)
1560 {
1561 return r;
1562 }
1563
1564 r = Sock_SetBlocking(listener, MI_FALSE);
1565
1566 if (r != MI_RESULT_OK)
1567 {
|
1568 krisbash 1.3 trace_SocketClose_SetBlockingFailed();
|
1569 mike 1.1 Sock_Close(listener);
1570 return r;
1571 }
1572 }
1573
1574 /* Watch for read events on the listener socket (client connections) */
1575 {
|
1576 krisbash 1.3 Http_Listener_SocketData* h = (Http_Listener_SocketData*)PAL_Calloc(1, sizeof(Http_Listener_SocketData));
|
1577 mike 1.1
1578 if (!h)
1579 {
|
1580 krisbash 1.3 trace_SocketClose_Http_Listener_SocketDataAllocFailed();
|
1581 mike 1.1 Sock_Close(listener);
1582 return MI_RESULT_FAILED;
1583 }
1584
1585 h->base.sock = listener;
1586 h->base.mask = SELECTOR_READ | SELECTOR_EXCEPTION;
1587 h->base.callback = _ListenerCallback;
1588 h->base.data = self;
1589 h->secure = secure;
1590
1591 r = Selector_AddHandler(self->selector, &h->base);
1592
1593 if (r != MI_RESULT_OK)
1594 {
|
1595 krisbash 1.3 trace_SocketClose_Selector_AddHandlerFailed();
|
1596 mike 1.1 Sock_Close(listener);
|
1597 krisbash 1.3 PAL_Free(h);
|
1598 mike 1.1 return r;
1599 }
1600 }
1601
1602 return MI_RESULT_OK;
1603 }
1604
1605 MI_Result Http_New_Server(
|
1606 krisbash 1.3 _Out_ Http** selfOut,
1607 _In_ Selector* selector, /* optional, maybe NULL*/
1608 _In_ unsigned short http_port, /* 0 to disable */
1609 _In_ unsigned short https_port, /* 0 to disable */
1610 _In_opt_z_ const char* sslCipherSuite, /* NULL to disable */
1611 _In_ Server_SSL_Options sslOptions, /* 0 for default options */
1612 _In_ OpenCallback callbackOnNewConnection,
1613 _In_opt_ void* callbackData,
1614 _In_opt_ const HttpOptions* options)
|
1615 mike 1.1 {
1616 Http* self;
1617 MI_Result r;
1618
1619 /* allocate this, inits selector */
|
1620 krisbash 1.3 r = _New_Http(selfOut, selector, callbackOnNewConnection, callbackData);
|
1621 mike 1.1
1622 if (MI_RESULT_OK != r)
1623 return r;
1624
1625 self = *selfOut;
1626
1627 /* Create http listener socket */
1628 if (http_port)
1629 {
1630 r = _CreateAddListenerSocket(self, http_port, MI_FALSE);
1631
1632 if (r != MI_RESULT_OK)
1633 {
1634 Http_Delete(self);
1635 return r;
1636 }
1637 }
1638
1639 #ifdef CONFIG_POSIX
1640 /* Create https listener socket */
1641 if (https_port)
1642 mike 1.1 {
1643 /* init ssl */
1644 SSL_library_init();
1645
1646 /* create context */
|
1647 krisbash 1.3 r = _CreateSSLContext(self, sslCipherSuite, sslOptions);
|
1648 mike 1.1
1649 if (r != MI_RESULT_OK)
1650 {
1651 Http_Delete(self);
1652 return r;
1653 }
1654
1655 /* create a socket */
1656 r = _CreateAddListenerSocket(self, https_port, MI_TRUE);
1657
1658 if (r != MI_RESULT_OK)
1659 {
1660 Http_Delete(self);
1661 return r;
1662 }
1663 }
1664 #else
1665 MI_UNUSED(https_port);
1666 #endif
1667
|
1668 krisbash 1.4 // options
|
1669 krisbash 1.3 if( NULL == options )
1670 {
1671 HttpOptions tmpOptions = DEFAULT_HTTP_OPTIONS;
1672 self->options = tmpOptions;
1673 }
1674 else
1675 {
1676 self->options = *options;
1677 }
1678
|
1679 mike 1.1 return MI_RESULT_OK;
1680 }
1681
1682 MI_Result Http_Delete(
1683 Http* self)
1684 {
1685 /* Check parameters */
1686 if (!self)
1687 return MI_RESULT_INVALID_PARAMETER;
1688
1689 /* Check magic number */
1690 if (self->magic != _MAGIC)
1691 return MI_RESULT_INVALID_PARAMETER;
1692
1693 if (self->internalSelectorUsed)
1694 {
1695 /* Release selector;
|
1696 krisbash 1.3 Note: selector-destory closes all sockets in a list including connector and listener */
|
1697 mike 1.1 Selector_Destroy(self->selector);
1698
1699 /* Shutdown the network */
1700 Sock_Stop();
1701 }
1702
1703 if (self->sslContext)
1704 SSL_CTX_free(self->sslContext);
1705
1706 /* Clear magic number */
1707 self->magic = 0xDDDDDDDD;
1708
1709 /* Free self pointer */
|
1710 krisbash 1.3 PAL_Free(self);
|
1711 mike 1.1
1712 return MI_RESULT_OK;
1713 }
1714
1715 MI_Result Http_Run(
1716 Http* self,
1717 MI_Uint64 timeoutUsec)
1718 {
1719 /* Run the selector */
|
1720 krisbash 1.3 return Selector_Run(self->selector, timeoutUsec, MI_FALSE);
|
1721 mike 1.1 }
|