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