00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdlib.h>
00026 #include <vlc/vlc.h>
00027
00028 #ifdef ENABLE_HTTPD
00029
00030 #include "vlc_httpd.h"
00031 #include "network.h"
00032 #include "vlc_tls.h"
00033 #include "vlc_acl.h"
00034
00035 #include <string.h>
00036 #include <errno.h>
00037
00038 #ifdef HAVE_UNISTD_H
00039 # include <unistd.h>
00040 #endif
00041
00042 #ifdef HAVE_FCNTL_H
00043 # include <fcntl.h>
00044 #endif
00045
00046 #if defined( UNDER_CE )
00047 # include <winsock.h>
00048 #elif defined( WIN32 )
00049 # include <winsock2.h>
00050 # include <ws2tcpip.h>
00051 #else
00052 # include <netdb.h>
00053 # include <sys/socket.h>
00054
00055 # include <netinet/in.h>
00056 # ifdef HAVE_ARPA_INET_H
00057 # include <arpa/inet.h>
00058 # endif
00059 #endif
00060
00061 #if defined( WIN32 )
00062
00063 #define HTTPD_CL_BUFSIZE 1000000
00064 #else
00065 #define HTTPD_CL_BUFSIZE 10000
00066 #endif
00067
00068 #if 0
00069 typedef struct httpd_t httpd_t;
00070
00071 typedef struct httpd_host_t httpd_host_t;
00072 typedef struct httpd_url_t httpd_url_t;
00073 typedef struct httpd_client_t httpd_client_t;
00074
00075 enum
00076 {
00077 HTTPD_MSG_NONE,
00078
00079
00080 HTTPD_MSG_ANSWER,
00081
00082
00083 HTTPD_MSG_CHANNEL,
00084
00085
00086 HTTPD_MSG_GET,
00087 HTTPD_MSG_HEAD,
00088 HTTPD_MSG_POST,
00089
00090
00091 HTTPD_MSG_OPTIONS,
00092 HTTPD_MSG_DESCRIBE,
00093 HTTPD_MSG_SETUP,
00094 HTTPD_MSG_PLAY,
00095 HTTPD_MSG_PAUSE,
00096 HTTPD_MSG_TEARDOWN,
00097
00098
00099 HTTPD_MSG_MAX
00100 };
00101
00102 enum
00103 {
00104 HTTPD_PROTO_NONE,
00105 HTTPD_PROTO_HTTP,
00106 HTTPD_PROTO_RTSP,
00107 };
00108
00109 typedef struct
00110 {
00111 httpd_client_t *cl;
00112
00113 int i_type;
00114 int i_proto;
00115 int i_version;
00116
00117
00118 int i_status;
00119 char *psz_status;
00120
00121
00122 char *psz_url;
00123 char *psz_args;
00124
00125
00126 int i_channel;
00127
00128
00129 int i_name;
00130 char **name;
00131 int i_value;
00132 char **value;
00133
00134
00135 int64_t i_body_offset;
00136 int i_body;
00137 uint8_t *p_body;
00138
00139 } httpd_message_t;
00140
00141 typedef struct httpd_callback_sys_t httpd_callback_sys_t;
00142
00143 typedef int (*httpd_callback_t)( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *answer, httpd_message_t *query );
00144
00145
00146
00147 httpd_host_t *httpd_HostNew( vlc_object_t *, char *psz_host, int i_port );
00148
00149 void httpd_HostDelete( httpd_host_t * );
00150
00151
00152 httpd_url_t *httpd_UrlNew( httpd_host_t *, char *psz_url );
00153
00154 int httpd_UrlCatch( httpd_url_t *, int i_msg,
00155 httpd_callback_t, httpd_callback_sys_t * );
00156
00157 void httpd_UrlDelete( httpd_url_t * );
00158
00159
00160 void httpd_ClientModeStream( httpd_client_t *cl );
00161 void httpd_ClientModeBidir( httpd_client_t *cl );
00162 static void httpd_ClientClean( httpd_client_t *cl );
00163
00164
00165 typedef struct httpd_file_t httpd_file_t;
00166 typedef struct httpd_file_sys_t httpd_file_sys_t;
00167 typedef int (*httpd_file_callback_t)( httpd_file_sys_t*, httpd_file_t *, uint8_t *psz_request, uint8_t **pp_data, int *pi_data );
00168 httpd_file_t *httpd_FileNew( httpd_host_t *,
00169 char *psz_url, char *psz_mime,
00170 char *psz_user, char *psz_password,
00171 httpd_file_callback_t pf_fill,
00172 httpd_file_sys_t *p_sys );
00173 void httpd_FileDelete( httpd_file_t * );
00174
00175 typedef struct httpd_redirect_t httpd_redirect_t;
00176 httpd_redirect_t *httpd_RedirectNew( httpd_host_t *, char *psz_url_dst, char *psz_url_src );
00177 void httpd_RedirectDelete( httpd_redirect_t * );
00178
00179 #if 0
00180 typedef struct httpd_stream_t httpd_stream_t;
00181 httpd_stream_t *httpd_StreamNew( httpd_host_t * );
00182 int httpd_StreamHeader( httpd_stream_t *, uint8_t *p_data, int i_data );
00183 int httpd_StreamSend( httpd_stream_t *, uint8_t *p_data, int i_data );
00184 void httpd_StreamDelete( httpd_stream_t * );
00185 #endif
00186
00187
00188 void httpd_MsgInit( httpd_message_t * );
00189 void httpd_MsgAdd( httpd_message_t *, char *psz_name, char *psz_value, ... );
00190
00191 char *httpd_MsgGet( httpd_message_t *, char *psz_name );
00192 void httpd_MsgClean( httpd_message_t * );
00193 #endif
00194
00195 #if 0
00196 struct httpd_t
00197 {
00198 VLC_COMMON_MEMBERS
00199
00200
00201 int i_host;
00202 httpd_host_t **host;
00203 };
00204 #endif
00205
00206 static void httpd_ClientClean( httpd_client_t *cl );
00207
00208
00209 struct httpd_host_t
00210 {
00211 VLC_COMMON_MEMBERS
00212
00213 httpd_t *httpd;
00214
00215
00216 int i_ref;
00217
00218
00219 char *psz_hostname;
00220 int i_port;
00221 int *fd;
00222
00223 vlc_mutex_t lock;
00224
00225
00226
00227
00228
00229 int i_url;
00230 httpd_url_t **url;
00231
00232 int i_client;
00233 httpd_client_t **client;
00234
00235
00236 tls_server_t *p_tls;
00237 };
00238
00239 struct httpd_url_t
00240 {
00241 httpd_host_t *host;
00242
00243 vlc_mutex_t lock;
00244
00245 char *psz_url;
00246 char *psz_user;
00247 char *psz_password;
00248 vlc_acl_t *p_acl;
00249
00250 struct
00251 {
00252 httpd_callback_t cb;
00253 httpd_callback_sys_t *p_sys;
00254 } catch[HTTPD_MSG_MAX];
00255 };
00256
00257
00258 enum
00259 {
00260 HTTPD_CLIENT_RECEIVING,
00261 HTTPD_CLIENT_RECEIVE_DONE,
00262
00263 HTTPD_CLIENT_SENDING,
00264 HTTPD_CLIENT_SEND_DONE,
00265
00266 HTTPD_CLIENT_WAITING,
00267
00268 HTTPD_CLIENT_DEAD,
00269
00270 HTTPD_CLIENT_TLS_HS_IN,
00271 HTTPD_CLIENT_TLS_HS_OUT
00272 };
00273
00274 enum
00275 {
00276 HTTPD_CLIENT_FILE,
00277 HTTPD_CLIENT_STREAM,
00278 HTTPD_CLIENT_BIDIR,
00279 };
00280
00281 struct httpd_client_t
00282 {
00283 httpd_url_t *url;
00284
00285 int i_ref;
00286
00287 struct sockaddr_storage sock;
00288 int i_sock_size;
00289 int fd;
00290
00291 int i_mode;
00292 int i_state;
00293 int b_read_waiting;
00294
00295 mtime_t i_activity_date;
00296 mtime_t i_activity_timeout;
00297
00298
00299 int i_buffer_size;
00300 int i_buffer;
00301 uint8_t *p_buffer;
00302
00303
00304 httpd_message_t query;
00305 httpd_message_t answer;
00306
00307
00308 tls_session_t *p_tls;
00309 };
00310
00311
00312
00313
00314
00315
00316 static void b64_decode( char *dest, char *src )
00317 {
00318 int i_level;
00319 int last = 0;
00320 int b64[256] = {
00321 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00322 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00323 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
00324 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
00325 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
00326 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
00327 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
00328 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
00329 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00330 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00331 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00332 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00333 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00334 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00335 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00336 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
00337 };
00338
00339 for( i_level = 0; *src != '\0'; src++ )
00340 {
00341 int c;
00342
00343 c = b64[(unsigned int)*src];
00344 if( c == -1 )
00345 {
00346 continue;
00347 }
00348
00349 switch( i_level )
00350 {
00351 case 0:
00352 i_level++;
00353 break;
00354 case 1:
00355 *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
00356 i_level++;
00357 break;
00358 case 2:
00359 *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
00360 i_level++;
00361 break;
00362 case 3:
00363 *dest++ = ( ( last &0x03 ) << 6 ) | c;
00364 i_level = 0;
00365 }
00366 last = c;
00367 }
00368
00369 *dest = '\0';
00370 }
00371
00372 static struct
00373 {
00374 const char *psz_ext;
00375 const char *psz_mime;
00376 } http_mime[] =
00377 {
00378 { ".htm", "text/html" },
00379 { ".html", "text/html" },
00380 { ".txt", "text/plain" },
00381 { ".xml", "text/xml" },
00382 { ".dtd", "text/dtd" },
00383
00384 { ".css", "text/css" },
00385
00386
00387 { ".gif", "image/gif" },
00388 { ".jpe", "image/jpeg" },
00389 { ".jpg", "image/jpeg" },
00390 { ".jpeg", "image/jpeg" },
00391 { ".png", "image/png" },
00392 { ".mpjpeg","multipart/x-mixed-replace; boundary=This Random String" },
00393
00394
00395 { ".avi", "video/avi" },
00396 { ".asf", "video/x-ms-asf" },
00397 { ".m1a", "audio/mpeg" },
00398 { ".m2a", "audio/mpeg" },
00399 { ".m1v", "video/mpeg" },
00400 { ".m2v", "video/mpeg" },
00401 { ".mp2", "audio/mpeg" },
00402 { ".mp3", "audio/mpeg" },
00403 { ".mpa", "audio/mpeg" },
00404 { ".mpg", "video/mpeg" },
00405 { ".mpeg", "video/mpeg" },
00406 { ".mpe", "video/mpeg" },
00407 { ".mov", "video/quicktime" },
00408 { ".moov", "video/quicktime" },
00409 { ".ogg", "application/ogg" },
00410 { ".ogm", "application/ogg" },
00411 { ".wav", "audio/wav" },
00412 { ".wma", "audio/x-ms-wma" },
00413 { ".wmv", "video/x-ms-wmv" },
00414
00415
00416
00417 { NULL, NULL }
00418 };
00419 static const char *httpd_MimeFromUrl( const char *psz_url )
00420 {
00421
00422 char *psz_ext;
00423
00424 psz_ext = strrchr( psz_url, '.' );
00425 if( psz_ext )
00426 {
00427 int i;
00428
00429 for( i = 0; http_mime[i].psz_ext != NULL ; i++ )
00430 {
00431 if( !strcasecmp( http_mime[i].psz_ext, psz_ext ) )
00432 {
00433 return http_mime[i].psz_mime;
00434 }
00435 }
00436 }
00437 return "application/octet-stream";
00438 }
00439
00440
00441
00442
00443 struct httpd_file_t
00444 {
00445 httpd_url_t *url;
00446
00447 char *psz_url;
00448 char *psz_mime;
00449
00450 httpd_file_callback_t pf_fill;
00451 httpd_file_sys_t *p_sys;
00452
00453 };
00454
00455
00456 static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query )
00457 {
00458 httpd_file_t *file = (httpd_file_t*)p_sys;
00459 uint8_t *psz_args = query->psz_args;
00460 uint8_t **pp_body, *p_body;
00461 int *pi_body, i_body;
00462
00463 if( answer == NULL || query == NULL )
00464 {
00465 return VLC_SUCCESS;
00466 }
00467 answer->i_proto = HTTPD_PROTO_HTTP;
00468 answer->i_version= query->i_version;
00469 answer->i_type = HTTPD_MSG_ANSWER;
00470
00471 answer->i_status = 200;
00472 answer->psz_status = strdup( "OK" );
00473
00474 httpd_MsgAdd( answer, "Content-type", "%s", file->psz_mime );
00475 httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
00476
00477 if( query->i_type != HTTPD_MSG_HEAD )
00478 {
00479 pp_body = &answer->p_body;
00480 pi_body = &answer->i_body;
00481 }
00482 else
00483 {
00484
00485 p_body = NULL;
00486 i_body = 0;
00487 pp_body = &p_body;
00488 pi_body = &i_body;
00489 }
00490
00491 if( query->i_type == HTTPD_MSG_POST )
00492 {
00493
00494 }
00495
00496 file->pf_fill( file->p_sys, file, psz_args, pp_body, pi_body );
00497
00498 if( query->i_type == HTTPD_MSG_HEAD && p_body != NULL )
00499 {
00500 free( p_body );
00501 }
00502
00503
00504 if( strcmp( httpd_MsgGet( &cl->query, "Connection" ), "" ) )
00505 {
00506 httpd_MsgAdd( answer, "Connection",
00507 httpd_MsgGet( &cl->query, "Connection" ) );
00508 }
00509
00510 httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
00511
00512 return VLC_SUCCESS;
00513 }
00514
00515
00516 httpd_file_t *httpd_FileNew( httpd_host_t *host,
00517 const char *psz_url, const char *psz_mime,
00518 const char *psz_user, const char *psz_password,
00519 const vlc_acl_t *p_acl, httpd_file_callback_t pf_fill,
00520 httpd_file_sys_t *p_sys )
00521 {
00522 httpd_file_t *file = malloc( sizeof( httpd_file_t ) );
00523
00524 if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user,
00525 psz_password, p_acl )
00526 ) == NULL )
00527 {
00528 free( file );
00529 return NULL;
00530 }
00531
00532 file->psz_url = strdup( psz_url );
00533 if( psz_mime && *psz_mime )
00534 {
00535 file->psz_mime = strdup( psz_mime );
00536 }
00537 else
00538 {
00539 file->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) );
00540 }
00541
00542 file->pf_fill = pf_fill;
00543 file->p_sys = p_sys;
00544
00545 httpd_UrlCatch( file->url, HTTPD_MSG_HEAD, httpd_FileCallBack,
00546 (httpd_callback_sys_t*)file );
00547 httpd_UrlCatch( file->url, HTTPD_MSG_GET, httpd_FileCallBack,
00548 (httpd_callback_sys_t*)file );
00549 httpd_UrlCatch( file->url, HTTPD_MSG_POST, httpd_FileCallBack,
00550 (httpd_callback_sys_t*)file );
00551
00552 return file;
00553 }
00554
00555 void httpd_FileDelete( httpd_file_t *file )
00556 {
00557 httpd_UrlDelete( file->url );
00558
00559 free( file->psz_url );
00560 free( file->psz_mime );
00561
00562 free( file );
00563 }
00564
00565
00566
00567
00568 struct httpd_handler_t
00569 {
00570 httpd_url_t *url;
00571
00572 httpd_handler_callback_t pf_fill;
00573 httpd_handler_sys_t *p_sys;
00574
00575 };
00576
00577 static int httpd_HandlerCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query )
00578 {
00579 httpd_handler_t *handler = (httpd_handler_t*)p_sys;
00580 uint8_t *psz_args = query->psz_args;
00581 char psz_remote_addr[100];
00582
00583 if( answer == NULL || query == NULL )
00584 {
00585 return VLC_SUCCESS;
00586 }
00587 answer->i_proto = HTTPD_PROTO_NONE;
00588 answer->i_type = HTTPD_MSG_ANSWER;
00589
00590
00591 answer->i_status = 0;
00592 answer->psz_status = NULL;
00593
00594 switch( cl->sock.ss_family )
00595 {
00596 #ifdef HAVE_INET_PTON
00597 case AF_INET:
00598 inet_ntop( cl->sock.ss_family,
00599 &((struct sockaddr_in *)&cl->sock)->sin_addr,
00600 psz_remote_addr, sizeof(psz_remote_addr) );
00601 break;
00602 case AF_INET6:
00603 inet_ntop( cl->sock.ss_family,
00604 &((struct sockaddr_in6 *)&cl->sock)->sin6_addr,
00605 psz_remote_addr, sizeof(psz_remote_addr) );
00606 break;
00607 #else
00608 case AF_INET:
00609 {
00610 char *psz_tmp = inet_ntoa( ((struct sockaddr_in *)&cl->sock)->sin_addr );
00611 strncpy( psz_remote_addr, psz_tmp, sizeof(psz_remote_addr) );
00612 break;
00613 }
00614 #endif
00615 default:
00616 psz_remote_addr[0] = '\0';
00617 }
00618
00619 handler->pf_fill( handler->p_sys, handler, query->psz_url, psz_args,
00620 query->i_type, query->p_body, query->i_body,
00621 psz_remote_addr, NULL,
00622 &answer->p_body, &answer->i_body );
00623
00624 if( query->i_type == HTTPD_MSG_HEAD )
00625 {
00626 char *p = answer->p_body;
00627 while ( (p = strchr( p, '\r' )) != NULL )
00628 {
00629 if( p[1] && p[1] == '\n' && p[2] && p[2] == '\r'
00630 && p[3] && p[3] == '\n' )
00631 {
00632 break;
00633 }
00634 }
00635 if( p != NULL )
00636 {
00637 p[4] = '\0';
00638 answer->i_body = strlen(answer->p_body) + 1;
00639 answer->p_body = realloc( answer->p_body, answer->i_body );
00640 }
00641 }
00642
00643 if( strncmp( answer->p_body, "HTTP/1.", 7 ) )
00644 {
00645 int i_status, i_headers;
00646 char *psz_headers, *psz_new, *psz_status;
00647 char psz_code[12];
00648 if( !strncmp( answer->p_body, "Status: ", 8 ) )
00649 {
00650
00651 i_status = strtol( &answer->p_body[8], &psz_headers, 0 );
00652 if( *psz_headers ) psz_headers++;
00653 if( *psz_headers ) psz_headers++;
00654 i_headers = answer->i_body - (psz_headers - (char *)answer->p_body);
00655 }
00656 else
00657 {
00658 i_status = 200;
00659 psz_headers = answer->p_body;
00660 i_headers = answer->i_body;
00661 }
00662 switch( i_status )
00663 {
00664 case 200:
00665 psz_status = "OK";
00666 break;
00667 case 401:
00668 psz_status = "Unauthorized";
00669 break;
00670 default:
00671 psz_status = "Undefined";
00672 break;
00673 }
00674 snprintf( psz_code, sizeof(psz_code), "%d", i_status );
00675 answer->i_body = sizeof("HTTP/1.0 \r\n") + strlen(psz_code)
00676 + strlen(psz_status) + i_headers - 1;
00677 psz_new = malloc( answer->i_body + 1);
00678 sprintf( psz_new, "HTTP/1.0 %s %s\r\n", psz_code, psz_status );
00679 memcpy( &psz_new[strlen(psz_new)], psz_headers, i_headers );
00680 free( answer->p_body );
00681 answer->p_body = psz_new;
00682 }
00683
00684 return VLC_SUCCESS;
00685 }
00686
00687 httpd_handler_t *httpd_HandlerNew( httpd_host_t *host, const char *psz_url,
00688 const char *psz_user,
00689 const char *psz_password,
00690 const vlc_acl_t *p_acl,
00691 httpd_handler_callback_t pf_fill,
00692 httpd_handler_sys_t *p_sys )
00693 {
00694 httpd_handler_t *handler = malloc( sizeof( httpd_handler_t ) );
00695
00696 if( ( handler->url = httpd_UrlNewUnique( host, psz_url, psz_user,
00697 psz_password, p_acl )
00698 ) == NULL )
00699 {
00700 free( handler );
00701 return NULL;
00702 }
00703
00704 handler->pf_fill = pf_fill;
00705 handler->p_sys = p_sys;
00706
00707 httpd_UrlCatch( handler->url, HTTPD_MSG_HEAD, httpd_HandlerCallBack,
00708 (httpd_callback_sys_t*)handler );
00709 httpd_UrlCatch( handler->url, HTTPD_MSG_GET, httpd_HandlerCallBack,
00710 (httpd_callback_sys_t*)handler );
00711 httpd_UrlCatch( handler->url, HTTPD_MSG_POST, httpd_HandlerCallBack,
00712 (httpd_callback_sys_t*)handler );
00713
00714 return handler;
00715 }
00716
00717 void httpd_HandlerDelete( httpd_handler_t *handler )
00718 {
00719 httpd_UrlDelete( handler->url );
00720 free( handler );
00721 }
00722
00723
00724
00725
00726 struct httpd_redirect_t
00727 {
00728 httpd_url_t *url;
00729 char *psz_dst;
00730 };
00731
00732 static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys,
00733 httpd_client_t *cl, httpd_message_t *answer,
00734 httpd_message_t *query )
00735 {
00736 httpd_redirect_t *rdir = (httpd_redirect_t*)p_sys;
00737 uint8_t *p;
00738
00739 if( answer == NULL || query == NULL )
00740 {
00741 return VLC_SUCCESS;
00742 }
00743 answer->i_proto = query->i_proto;
00744 answer->i_version= query->i_version;
00745 answer->i_type = HTTPD_MSG_ANSWER;
00746 answer->i_status = 301;
00747 answer->psz_status = strdup( "Moved Permanently" );
00748
00749 p = answer->p_body = malloc( 1000 + strlen( rdir->psz_dst ) );
00750 p += sprintf( (char *)p,
00751 "<?xml version=\"1.0\" encoding=\"ascii\" ?>\n"
00752 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
00753 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
00754 "<html>\n"
00755 "<head>\n"
00756 "<title>Redirection</title>\n"
00757 "</head>\n"
00758 "<body>\n"
00759 "<h1>You should be "
00760 "<a href=\"%s\">redirected</a></h1>\n"
00761 "<hr />\n"
00762 "<p><a href=\"http://www.videolan.org\">VideoLAN</a>\n</p>"
00763 "<hr />\n"
00764 "</body>\n"
00765 "</html>\n", rdir->psz_dst );
00766 answer->i_body = p - answer->p_body;
00767
00768
00769 httpd_MsgAdd( answer, "Location", "%s", rdir->psz_dst );
00770
00771 httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
00772
00773 return VLC_SUCCESS;
00774 }
00775
00776 httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, const char *psz_url_dst,
00777 const char *psz_url_src )
00778 {
00779 httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) );
00780
00781 if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL, NULL ) ) )
00782 {
00783 free( rdir );
00784 return NULL;
00785 }
00786 rdir->psz_dst = strdup( psz_url_dst );
00787
00788
00789 httpd_UrlCatch( rdir->url, HTTPD_MSG_HEAD, httpd_RedirectCallBack,
00790 (httpd_callback_sys_t*)rdir );
00791 httpd_UrlCatch( rdir->url, HTTPD_MSG_GET, httpd_RedirectCallBack,
00792 (httpd_callback_sys_t*)rdir );
00793 httpd_UrlCatch( rdir->url, HTTPD_MSG_POST, httpd_RedirectCallBack,
00794 (httpd_callback_sys_t*)rdir );
00795 httpd_UrlCatch( rdir->url, HTTPD_MSG_DESCRIBE, httpd_RedirectCallBack,
00796 (httpd_callback_sys_t*)rdir );
00797
00798 return rdir;
00799 }
00800 void httpd_RedirectDelete( httpd_redirect_t *rdir )
00801 {
00802 httpd_UrlDelete( rdir->url );
00803 free( rdir->psz_dst );
00804 free( rdir );
00805 }
00806
00807
00808
00809
00810 struct httpd_stream_t
00811 {
00812 vlc_mutex_t lock;
00813 httpd_url_t *url;
00814
00815 char *psz_mime;
00816
00817
00818 uint8_t *p_header;
00819 int i_header;
00820
00821
00822 int i_buffer_size;
00823 uint8_t *p_buffer;
00824 int64_t i_buffer_pos;
00825 int64_t i_buffer_last_pos;
00826 };
00827
00828 static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
00829 httpd_client_t *cl, httpd_message_t *answer,
00830 httpd_message_t *query )
00831 {
00832 httpd_stream_t *stream = (httpd_stream_t*)p_sys;
00833
00834 if( answer == NULL || query == NULL || cl == NULL )
00835 {
00836 return VLC_SUCCESS;
00837 }
00838 if( answer->i_body_offset > 0 )
00839 {
00840 int64_t i_write;
00841 int i_pos;
00842
00843 #if 0
00844 fprintf( stderr, "httpd_StreamCallBack i_body_offset=%lld\n",
00845 answer->i_body_offset );
00846 #endif
00847
00848 if( answer->i_body_offset >= stream->i_buffer_pos )
00849 {
00850
00851 return VLC_EGENERIC;
00852 }
00853 if( answer->i_body_offset + stream->i_buffer_size <
00854 stream->i_buffer_pos )
00855 {
00856
00857 fprintf( stderr, "fixing i_body_offset (old=%lld new=%lld)\n",
00858 answer->i_body_offset, stream->i_buffer_last_pos );
00859 answer->i_body_offset = stream->i_buffer_last_pos;
00860 }
00861
00862 i_pos = answer->i_body_offset % stream->i_buffer_size;
00863 i_write = stream->i_buffer_pos - answer->i_body_offset;
00864 if( i_write > HTTPD_CL_BUFSIZE )
00865 {
00866 i_write = HTTPD_CL_BUFSIZE;
00867 }
00868 else if( i_write <= 0 )
00869 {
00870 return VLC_EGENERIC;
00871 }
00872
00873
00874 i_write = __MIN( i_write, stream->i_buffer_size - i_pos );
00875
00876
00877 answer->i_proto = HTTPD_PROTO_HTTP;
00878 answer->i_version= 0;
00879 answer->i_type = HTTPD_MSG_ANSWER;
00880
00881 answer->i_body = i_write;
00882 answer->p_body = malloc( i_write );
00883 memcpy( answer->p_body, &stream->p_buffer[i_pos], i_write );
00884
00885 answer->i_body_offset += i_write;
00886
00887 return VLC_SUCCESS;
00888 }
00889 else
00890 {
00891 answer->i_proto = HTTPD_PROTO_HTTP;
00892 answer->i_version= 0;
00893 answer->i_type = HTTPD_MSG_ANSWER;
00894
00895 answer->i_status = 200;
00896 answer->psz_status = strdup( "OK" );
00897
00898 if( query->i_type != HTTPD_MSG_HEAD )
00899 {
00900 httpd_ClientModeStream( cl );
00901 vlc_mutex_lock( &stream->lock );
00902
00903 if( stream->i_header > 0 )
00904 {
00905 answer->i_body = stream->i_header;
00906 answer->p_body = malloc( stream->i_header );
00907 memcpy( answer->p_body, stream->p_header, stream->i_header );
00908 }
00909 answer->i_body_offset = stream->i_buffer_last_pos;
00910 vlc_mutex_unlock( &stream->lock );
00911 }
00912 else
00913 {
00914 httpd_MsgAdd( answer, "Content-Length", "%d", 0 );
00915 answer->i_body_offset = 0;
00916 }
00917
00918 if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) )
00919 {
00920 vlc_bool_t b_xplaystream = VLC_FALSE;
00921 int i;
00922
00923 httpd_MsgAdd( answer, "Content-type", "%s",
00924 "application/octet-stream" );
00925 httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" );
00926 httpd_MsgAdd( answer, "Pragma", "no-cache" );
00927 httpd_MsgAdd( answer, "Pragma", "client-id=%d", rand()&0x7fff );
00928 httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" );
00929
00930
00931 for( i = 0; i < query->i_name; i++ )
00932 {
00933 if( !strcasecmp( query->name[i], "Pragma" ) &&
00934 strstr( query->value[i], "xPlayStrm=1" ) )
00935 {
00936 b_xplaystream = VLC_TRUE;
00937 }
00938 }
00939
00940 if( !b_xplaystream )
00941 {
00942 answer->i_body_offset = 0;
00943 }
00944 }
00945 else
00946 {
00947 httpd_MsgAdd( answer, "Content-type", "%s", stream->psz_mime );
00948 }
00949 httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
00950 return VLC_SUCCESS;
00951 }
00952 }
00953
00954 httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
00955 const char *psz_url, const char *psz_mime,
00956 const char *psz_user, const char *psz_password,
00957 const vlc_acl_t *p_acl )
00958 {
00959 httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) );
00960
00961 if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user,
00962 psz_password, p_acl )
00963 ) == NULL )
00964 {
00965 free( stream );
00966 return NULL;
00967 }
00968 vlc_mutex_init( host, &stream->lock );
00969 if( psz_mime && *psz_mime )
00970 {
00971 stream->psz_mime = strdup( psz_mime );
00972 }
00973 else
00974 {
00975 stream->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) );
00976 }
00977 stream->i_header = 0;
00978 stream->p_header = NULL;
00979 stream->i_buffer_size = 5000000;
00980 stream->p_buffer = malloc( stream->i_buffer_size );
00981
00982
00983 stream->i_buffer_pos = 1;
00984 stream->i_buffer_last_pos = 1;
00985
00986 httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack,
00987 (httpd_callback_sys_t*)stream );
00988 httpd_UrlCatch( stream->url, HTTPD_MSG_GET, httpd_StreamCallBack,
00989 (httpd_callback_sys_t*)stream );
00990 httpd_UrlCatch( stream->url, HTTPD_MSG_POST, httpd_StreamCallBack,
00991 (httpd_callback_sys_t*)stream );
00992
00993 return stream;
00994 }
00995
00996 int httpd_StreamHeader( httpd_stream_t *stream, uint8_t *p_data, int i_data )
00997 {
00998 vlc_mutex_lock( &stream->lock );
00999 if( stream->p_header )
01000 {
01001 free( stream->p_header );
01002 stream->p_header = NULL;
01003 }
01004 stream->i_header = i_data;
01005 if( i_data > 0 )
01006 {
01007 stream->p_header = malloc( i_data );
01008 memcpy( stream->p_header, p_data, i_data );
01009 }
01010 vlc_mutex_unlock( &stream->lock );
01011
01012 return VLC_SUCCESS;
01013 }
01014
01015 int httpd_StreamSend( httpd_stream_t *stream, uint8_t *p_data, int i_data )
01016 {
01017 int i_count;
01018 int i_pos;
01019
01020 if( i_data < 0 || p_data == NULL )
01021 {
01022 return VLC_SUCCESS;
01023 }
01024 vlc_mutex_lock( &stream->lock );
01025
01026
01027 stream->i_buffer_last_pos = stream->i_buffer_pos;
01028
01029 i_pos = stream->i_buffer_pos % stream->i_buffer_size;
01030 i_count = i_data;
01031 while( i_count > 0)
01032 {
01033 int i_copy;
01034
01035 i_copy = __MIN( i_count, stream->i_buffer_size - i_pos );
01036
01037
01038 memcpy( &stream->p_buffer[i_pos], p_data, i_copy );
01039
01040 i_pos = ( i_pos + i_copy ) % stream->i_buffer_size;
01041 i_count -= i_copy;
01042 p_data += i_copy;
01043 }
01044
01045 stream->i_buffer_pos += i_data;
01046
01047 vlc_mutex_unlock( &stream->lock );
01048 return VLC_SUCCESS;
01049 }
01050
01051 void httpd_StreamDelete( httpd_stream_t *stream )
01052 {
01053 httpd_UrlDelete( stream->url );
01054 vlc_mutex_destroy( &stream->lock );
01055 if( stream->psz_mime ) free( stream->psz_mime );
01056 if( stream->p_header ) free( stream->p_header );
01057 if( stream->p_buffer ) free( stream->p_buffer );
01058 free( stream );
01059 }
01060
01061
01062
01063
01064
01065 static void httpd_HostThread( httpd_host_t * );
01066
01067
01068 httpd_host_t *httpd_HostNew( vlc_object_t *p_this, const char *psz_host,
01069 int i_port )
01070 {
01071 return httpd_TLSHostNew( p_this, psz_host, i_port, NULL, NULL, NULL, NULL
01072 );
01073 }
01074
01075 httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname,
01076 int i_port,
01077 const char *psz_cert, const char *psz_key,
01078 const char *psz_ca, const char *psz_crl )
01079 {
01080 httpd_t *httpd;
01081 httpd_host_t *host;
01082 tls_server_t *p_tls;
01083 char *psz_host;
01084 vlc_value_t lockval;
01085 int i;
01086
01087 if( psz_hostname == NULL )
01088 psz_hostname = "";
01089
01090 psz_host = strdup( psz_hostname );
01091 if( psz_host == NULL )
01092 {
01093 msg_Err( p_this, "memory error" );
01094 return NULL;
01095 }
01096
01097
01098 var_Create( p_this->p_libvlc, "httpd_mutex", VLC_VAR_MUTEX );
01099 var_Get( p_this->p_libvlc, "httpd_mutex", &lockval );
01100 vlc_mutex_lock( lockval.p_address );
01101
01102 if( !(httpd = vlc_object_find( p_this, VLC_OBJECT_HTTPD, FIND_ANYWHERE )) )
01103 {
01104 msg_Info( p_this, "creating httpd" );
01105 if( ( httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD ) ) == NULL )
01106 {
01107 vlc_mutex_unlock( lockval.p_address );
01108 free( psz_host );
01109 return NULL;
01110 }
01111
01112 httpd->i_host = 0;
01113 httpd->host = NULL;
01114
01115 vlc_object_yield( httpd );
01116 vlc_object_attach( httpd, p_this->p_vlc );
01117 }
01118
01119
01120 for( i = httpd->i_host - 1; i >= 0; i-- )
01121 {
01122 host = httpd->host[i];
01123
01124
01125 if( ( ( httpd->host[i]->p_tls != NULL ) != ( psz_cert != NULL ) )
01126 || ( host->i_port != i_port )
01127 || strcmp( host->psz_hostname, psz_hostname ) )
01128 continue;
01129
01130
01131 host->i_ref++;
01132
01133 vlc_mutex_unlock( lockval.p_address );
01134 return host;
01135 }
01136
01137 host = NULL;
01138
01139
01140 if ( psz_cert != NULL )
01141 {
01142 p_tls = tls_ServerCreate( p_this, psz_cert, psz_key );
01143 if ( p_tls == NULL )
01144 {
01145 msg_Err( p_this, "TLS initialization error" );
01146 goto error;
01147 }
01148
01149 if ( ( psz_ca != NULL) && tls_ServerAddCA( p_tls, psz_ca ) )
01150 {
01151 msg_Err( p_this, "TLS CA error" );
01152 goto error;
01153 }
01154
01155 if ( ( psz_crl != NULL) && tls_ServerAddCRL( p_tls, psz_crl ) )
01156 {
01157 msg_Err( p_this, "TLS CRL error" );
01158 goto error;
01159 }
01160 }
01161 else
01162 p_tls = NULL;
01163
01164
01165 host = vlc_object_create( p_this, sizeof( httpd_host_t ) );
01166 host->httpd = httpd;
01167 vlc_mutex_init( httpd, &host->lock );
01168 host->i_ref = 1;
01169
01170 host->fd = net_ListenTCP( p_this, psz_host, i_port );
01171 if( host->fd == NULL )
01172 {
01173 msg_Err( p_this, "cannot create socket(s) for HTTP host" );
01174 goto error;
01175 }
01176
01177 host->i_port = i_port;
01178 host->psz_hostname = psz_host;
01179
01180 host->i_url = 0;
01181 host->url = NULL;
01182 host->i_client = 0;
01183 host->client = NULL;
01184
01185 host->p_tls = p_tls;
01186
01187
01188 if( vlc_thread_create( host, "httpd host thread", httpd_HostThread,
01189 VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
01190 {
01191 msg_Err( p_this, "cannot spawn http host thread" );
01192 goto error;
01193 }
01194
01195
01196 TAB_APPEND( httpd->i_host, httpd->host, host );
01197 vlc_mutex_unlock( lockval.p_address );
01198
01199 return host;
01200
01201 error:
01202 free( psz_host );
01203 if( httpd->i_host <= 0 )
01204 {
01205 vlc_object_release( httpd );
01206 vlc_object_detach( httpd );
01207 vlc_object_destroy( httpd );
01208 }
01209 vlc_mutex_unlock( lockval.p_address );
01210
01211 if( host != NULL )
01212 {
01213 net_ListenClose( host->fd );
01214 vlc_mutex_destroy( &host->lock );
01215 vlc_object_destroy( host );
01216 }
01217
01218 if( p_tls != NULL )
01219 tls_ServerDelete( p_tls );
01220
01221 return NULL;
01222 }
01223
01224
01225 void httpd_HostDelete( httpd_host_t *host )
01226 {
01227 httpd_t *httpd = host->httpd;
01228 vlc_value_t lockval;
01229 int i;
01230
01231 msg_Dbg( host, "httpd_HostDelete" );
01232
01233 var_Get( httpd->p_libvlc, "httpd_mutex", &lockval );
01234 vlc_mutex_lock( lockval.p_address );
01235
01236 host->i_ref--;
01237 if( host->i_ref > 0 )
01238 {
01239
01240 vlc_mutex_unlock( lockval.p_address );
01241 msg_Dbg( host, "httpd_HostDelete: host still used" );
01242 return;
01243 }
01244 TAB_REMOVE( httpd->i_host, httpd->host, host );
01245
01246 msg_Dbg( host, "httpd_HostDelete: host removed from http" );
01247
01248 host->b_die = 1;
01249 vlc_thread_join( host );
01250
01251 msg_Dbg( host, "httpd_HostDelete: host thread joined" );
01252
01253 for( i = 0; i < host->i_url; i++ )
01254 {
01255 msg_Err( host, "url still registered:%s", host->url[i]->psz_url );
01256 }
01257 for( i = 0; i < host->i_client; i++ )
01258 {
01259 httpd_client_t *cl = host->client[i];
01260 msg_Warn( host, "client still connected" );
01261 httpd_ClientClean( cl );
01262 TAB_REMOVE( host->i_client, host->client, cl );
01263 free( cl );
01264 i--;
01265
01266 }
01267
01268 if( host->p_tls != NULL)
01269 tls_ServerDelete( host->p_tls );
01270
01271 net_ListenClose( host->fd );
01272 free( host->psz_hostname );
01273
01274 vlc_mutex_destroy( &host->lock );
01275 vlc_object_destroy( host );
01276
01277 vlc_object_release( httpd );
01278 if( httpd->i_host <= 0 )
01279 {
01280 msg_Info( httpd, "httpd doesn't reference any host, deleting" );
01281 vlc_object_detach( httpd );
01282 vlc_object_destroy( httpd );
01283 }
01284 vlc_mutex_unlock( lockval.p_address );
01285 }
01286
01287
01288 static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, const char *psz_url,
01289 const char *psz_user, const char *psz_password,
01290 const vlc_acl_t *p_acl, vlc_bool_t b_check )
01291 {
01292 httpd_url_t *url;
01293 int i;
01294
01295 vlc_mutex_lock( &host->lock );
01296 if( b_check )
01297 {
01298 for( i = 0; i < host->i_url; i++ )
01299 {
01300 if( !strcmp( psz_url, host->url[i]->psz_url ) )
01301 {
01302 msg_Warn( host->httpd,
01303 "cannot add '%s' (url already defined)", psz_url );
01304 vlc_mutex_unlock( &host->lock );
01305 return NULL;
01306 }
01307 }
01308 }
01309
01310 url = malloc( sizeof( httpd_url_t ) );
01311 url->host = host;
01312
01313 vlc_mutex_init( host->httpd, &url->lock );
01314 url->psz_url = strdup( psz_url );
01315 url->psz_user = strdup( psz_user ? psz_user : "" );
01316 url->psz_password = strdup( psz_password ? psz_password : "" );
01317 url->p_acl = ACL_Duplicate( host, p_acl );
01318 for( i = 0; i < HTTPD_MSG_MAX; i++ )
01319 {
01320 url->catch[i].cb = NULL;
01321 url->catch[i].p_sys = NULL;
01322 }
01323
01324 TAB_APPEND( host->i_url, host->url, url );
01325 vlc_mutex_unlock( &host->lock );
01326
01327 return url;
01328 }
01329
01330 httpd_url_t *httpd_UrlNew( httpd_host_t *host, const char *psz_url,
01331 const char *psz_user, const char *psz_password,
01332 const vlc_acl_t *p_acl )
01333 {
01334 return httpd_UrlNewPrivate( host, psz_url, psz_user,
01335 psz_password, p_acl, VLC_FALSE );
01336 }
01337
01338 httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, const char *psz_url,
01339 const char *psz_user, const char *psz_password,
01340 const vlc_acl_t *p_acl )
01341 {
01342 return httpd_UrlNewPrivate( host, psz_url, psz_user,
01343 psz_password, p_acl, VLC_TRUE );
01344 }
01345
01346
01347 int httpd_UrlCatch( httpd_url_t *url, int i_msg, httpd_callback_t cb,
01348 httpd_callback_sys_t *p_sys )
01349 {
01350 vlc_mutex_lock( &url->lock );
01351 url->catch[i_msg].cb = cb;
01352 url->catch[i_msg].p_sys= p_sys;
01353 vlc_mutex_unlock( &url->lock );
01354
01355 return VLC_SUCCESS;
01356 }
01357
01358
01359
01360 void httpd_UrlDelete( httpd_url_t *url )
01361 {
01362 httpd_host_t *host = url->host;
01363 int i;
01364
01365 vlc_mutex_lock( &host->lock );
01366 TAB_REMOVE( host->i_url, host->url, url );
01367
01368 vlc_mutex_destroy( &url->lock );
01369 free( url->psz_url );
01370 free( url->psz_user );
01371 free( url->psz_password );
01372 ACL_Destroy( url->p_acl );
01373
01374 for( i = 0; i < host->i_client; i++ )
01375 {
01376 httpd_client_t *client = host->client[i];
01377
01378 if( client->url == url )
01379 {
01380
01381 msg_Warn( host, "force closing connections" );
01382 httpd_ClientClean( client );
01383 TAB_REMOVE( host->i_client, host->client, client );
01384 free( client );
01385 i--;
01386 }
01387 }
01388 free( url );
01389 vlc_mutex_unlock( &host->lock );
01390 }
01391
01392 void httpd_MsgInit( httpd_message_t *msg )
01393 {
01394 msg->cl = NULL;
01395 msg->i_type = HTTPD_MSG_NONE;
01396 msg->i_proto = HTTPD_PROTO_NONE;
01397 msg->i_version = -1;
01398
01399 msg->i_status = 0;
01400 msg->psz_status = NULL;
01401
01402 msg->psz_url = NULL;
01403 msg->psz_args = NULL;
01404
01405 msg->i_channel = -1;
01406
01407 msg->i_name = 0;
01408 msg->name = NULL;
01409 msg->i_value= 0;
01410 msg->value = NULL;
01411
01412 msg->i_body_offset = 0;
01413 msg->i_body = 0;
01414 msg->p_body = 0;
01415 }
01416
01417 void httpd_MsgClean( httpd_message_t *msg )
01418 {
01419 int i;
01420
01421 if( msg->psz_status )
01422 {
01423 free( msg->psz_status );
01424 }
01425 if( msg->psz_url )
01426 {
01427 free( msg->psz_url );
01428 }
01429 if( msg->psz_args )
01430 {
01431 free( msg->psz_args );
01432 }
01433 for( i = 0; i < msg->i_name; i++ )
01434 {
01435 free( msg->name[i] );
01436 free( msg->value[i] );
01437 }
01438 if( msg->name )
01439 {
01440 free( msg->name );
01441 }
01442 if( msg->value )
01443 {
01444 free( msg->value );
01445 }
01446 if( msg->p_body )
01447 {
01448 free( msg->p_body );
01449 }
01450 httpd_MsgInit( msg );
01451 }
01452
01453 char *httpd_MsgGet( httpd_message_t *msg, char *name )
01454 {
01455 int i;
01456
01457 for( i = 0; i < msg->i_name; i++ )
01458 {
01459 if( !strcasecmp( msg->name[i], name ))
01460 {
01461 return msg->value[i];
01462 }
01463 }
01464 return "";
01465 }
01466 void httpd_MsgAdd( httpd_message_t *msg, char *name, char *psz_value, ... )
01467 {
01468 va_list args;
01469 char *value = NULL;
01470
01471 va_start( args, psz_value );
01472 #if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN) && !defined(SYS_BEOS)
01473 vasprintf( &value, psz_value, args );
01474 #else
01475 {
01476 int i_size = strlen( psz_value ) + 4096;
01477 value = calloc( i_size, sizeof( char ) );
01478 vsnprintf( value, i_size, psz_value, args );
01479 value[i_size - 1] = 0;
01480 }
01481 #endif
01482 va_end( args );
01483
01484 name = strdup( name );
01485
01486 TAB_APPEND( msg->i_name, msg->name, name );
01487 TAB_APPEND( msg->i_value, msg->value, value );
01488 }
01489
01490 static void httpd_ClientInit( httpd_client_t *cl )
01491 {
01492 cl->i_state = HTTPD_CLIENT_RECEIVING;
01493 cl->i_activity_date = mdate();
01494 cl->i_activity_timeout = I64C(10000000);
01495 cl->i_buffer_size = HTTPD_CL_BUFSIZE;
01496 cl->i_buffer = 0;
01497 cl->p_buffer = malloc( cl->i_buffer_size );
01498 cl->i_mode = HTTPD_CLIENT_FILE;
01499 cl->b_read_waiting = VLC_FALSE;
01500
01501 httpd_MsgInit( &cl->query );
01502 httpd_MsgInit( &cl->answer );
01503 }
01504
01505 void httpd_ClientModeStream( httpd_client_t *cl )
01506 {
01507 cl->i_mode = HTTPD_CLIENT_STREAM;
01508 }
01509
01510 void httpd_ClientModeBidir( httpd_client_t *cl )
01511 {
01512 cl->i_mode = HTTPD_CLIENT_BIDIR;
01513 }
01514
01515 char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip )
01516 {
01517 return net_GetPeerAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;
01518 }
01519
01520 char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip )
01521 {
01522 return net_GetSockAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;
01523 }
01524
01525 static void httpd_ClientClean( httpd_client_t *cl )
01526 {
01527 if( cl->fd >= 0 )
01528 {
01529 if( cl->p_tls != NULL )
01530 tls_ServerSessionClose( cl->p_tls );
01531 net_Close( cl->fd );
01532 cl->fd = -1;
01533 }
01534
01535 httpd_MsgClean( &cl->answer );
01536 httpd_MsgClean( &cl->query );
01537
01538 if( cl->p_buffer )
01539 {
01540 free( cl->p_buffer );
01541 cl->p_buffer = NULL;
01542 }
01543 }
01544
01545 static httpd_client_t *httpd_ClientNew( int fd, struct sockaddr_storage *sock,
01546 int i_sock_size,
01547 tls_session_t *p_tls )
01548 {
01549 httpd_client_t *cl = malloc( sizeof( httpd_client_t ) );
01550 cl->i_ref = 0;
01551 cl->fd = fd;
01552 memcpy( &cl->sock, sock, sizeof( cl->sock ) );
01553 cl->i_sock_size = i_sock_size;
01554 cl->url = NULL;
01555 cl->p_tls = p_tls;
01556
01557 httpd_ClientInit( cl );
01558
01559 return cl;
01560 }
01561
01562
01563 static int httpd_NetRecv( httpd_client_t *cl, uint8_t *p, int i_len )
01564 {
01565 tls_session_t *p_tls;
01566
01567 p_tls = cl->p_tls;
01568 if( p_tls != NULL)
01569 return tls_Recv( p_tls, p, i_len );
01570
01571 return recv( cl->fd, p, i_len, 0 );
01572 }
01573
01574
01575 static int httpd_NetSend( httpd_client_t *cl, const uint8_t *p, int i_len )
01576 {
01577 tls_session_t *p_tls;
01578
01579 p_tls = cl->p_tls;
01580 if( p_tls != NULL)
01581 return tls_Send( p_tls, p, i_len );
01582
01583 return send( cl->fd, p, i_len, 0 );
01584 }
01585
01586
01587 static void httpd_ClientRecv( httpd_client_t *cl )
01588 {
01589 int i_len;
01590
01591 if( cl->query.i_proto == HTTPD_PROTO_NONE )
01592 {
01593
01594 i_len = httpd_NetRecv( cl, &cl->p_buffer[cl->i_buffer],
01595 4 - cl->i_buffer );
01596 if( i_len > 0 )
01597 {
01598 cl->i_buffer += i_len;
01599 }
01600
01601 if( cl->i_buffer >= 4 )
01602 {
01603
01604
01605 if( cl->p_buffer[0] == '$' )
01606 {
01607
01608 cl->query.i_proto = HTTPD_PROTO_RTSP;
01609 cl->query.i_type = HTTPD_MSG_CHANNEL;
01610 cl->query.i_channel = cl->p_buffer[1];
01611 cl->query.i_body = (cl->p_buffer[2] << 8)|cl->p_buffer[3];
01612 cl->query.p_body = malloc( cl->query.i_body );
01613
01614 cl->i_buffer = 0;
01615 }
01616 else if( !memcmp( cl->p_buffer, "HTTP", 4 ) )
01617 {
01618 cl->query.i_proto = HTTPD_PROTO_HTTP;
01619 cl->query.i_type = HTTPD_MSG_ANSWER;
01620 }
01621 else if( !memcmp( cl->p_buffer, "RTSP", 4 ) )
01622 {
01623 cl->query.i_proto = HTTPD_PROTO_RTSP;
01624 cl->query.i_type = HTTPD_MSG_ANSWER;
01625 }
01626 else if( !memcmp( cl->p_buffer, "GET", 3 ) ||
01627 !memcmp( cl->p_buffer, "HEAD", 4 ) ||
01628 !memcmp( cl->p_buffer, "POST", 4 ) )
01629 {
01630 cl->query.i_proto = HTTPD_PROTO_HTTP;
01631 cl->query.i_type = HTTPD_MSG_NONE;
01632 }
01633 else
01634 {
01635 cl->query.i_proto = HTTPD_PROTO_RTSP;
01636 cl->query.i_type = HTTPD_MSG_NONE;
01637 }
01638 }
01639 }
01640 else if( cl->query.i_body > 0 )
01641 {
01642
01643 i_len = httpd_NetRecv( cl, &cl->query.p_body[cl->i_buffer],
01644 cl->query.i_body - cl->i_buffer );
01645 if( i_len > 0 )
01646 {
01647 cl->i_buffer += i_len;
01648 }
01649 if( cl->i_buffer >= cl->query.i_body )
01650 {
01651 cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
01652 }
01653 }
01654 else
01655 {
01656
01657 for( ;; )
01658 {
01659 i_len = httpd_NetRecv (cl, &cl->p_buffer[cl->i_buffer], 1 );
01660 if( i_len <= 0 )
01661 {
01662 break;
01663 }
01664 cl->i_buffer++;
01665
01666 if( cl->i_buffer + 1 >= cl->i_buffer_size )
01667 {
01668 cl->i_buffer_size += 1024;
01669 cl->p_buffer = realloc( cl->p_buffer, cl->i_buffer_size );
01670 }
01671 if( ( cl->i_buffer >= 2 && !memcmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )||
01672 ( cl->i_buffer >= 4 && !memcmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) )
01673 {
01674 char *p;
01675
01676
01677 cl->p_buffer[cl->i_buffer] = '\0';
01678
01679 if( cl->query.i_type == HTTPD_MSG_ANSWER )
01680 {
01681
01682
01683
01684 cl->query.i_status =
01685 strtol( (char *)&cl->p_buffer[8],
01686 &p, 0 );
01687 while( *p == ' ' )
01688 {
01689 p++;
01690 }
01691 cl->query.psz_status = strdup( p );
01692 }
01693 else
01694 {
01695 static const struct
01696 {
01697 char *name;
01698 int i_type;
01699 int i_proto;
01700 }
01701 msg_type[] =
01702 {
01703 { "GET", HTTPD_MSG_GET, HTTPD_PROTO_HTTP },
01704 { "HEAD", HTTPD_MSG_HEAD, HTTPD_PROTO_HTTP },
01705 { "POST", HTTPD_MSG_POST, HTTPD_PROTO_HTTP },
01706
01707 { "OPTIONS", HTTPD_MSG_OPTIONS, HTTPD_PROTO_RTSP },
01708 { "DESCRIBE", HTTPD_MSG_DESCRIBE, HTTPD_PROTO_RTSP },
01709 { "SETUP", HTTPD_MSG_SETUP, HTTPD_PROTO_RTSP },
01710 { "PLAY", HTTPD_MSG_PLAY, HTTPD_PROTO_RTSP },
01711 { "PAUSE", HTTPD_MSG_PAUSE, HTTPD_PROTO_RTSP },
01712 { "TEARDOWN", HTTPD_MSG_TEARDOWN, HTTPD_PROTO_RTSP },
01713
01714 { NULL, HTTPD_MSG_NONE, HTTPD_PROTO_NONE }
01715 };
01716 int i;
01717
01718 p = NULL;
01719 cl->query.i_type = HTTPD_MSG_NONE;
01720
01721
01722
01723 for( i = 0; msg_type[i].name != NULL; i++ )
01724 {
01725 if( !strncmp( (char *)cl->p_buffer, msg_type[i].name,
01726 strlen( msg_type[i].name ) ) )
01727 {
01728 p = (char *)&cl->p_buffer[strlen((char *)msg_type[i].name) + 1 ];
01729 cl->query.i_type = msg_type[i].i_type;
01730 if( cl->query.i_proto != msg_type[i].i_proto )
01731 {
01732 p = NULL;
01733 cl->query.i_proto = HTTPD_PROTO_NONE;
01734 cl->query.i_type = HTTPD_MSG_NONE;
01735 }
01736 break;
01737 }
01738 }
01739 if( p == NULL )
01740 {
01741 if( strstr( (char *)cl->p_buffer, "HTTP/1." ) )
01742 {
01743 cl->query.i_proto = HTTPD_PROTO_HTTP;
01744 }
01745 else if( strstr( (char *)cl->p_buffer, "RTSP/1." ) )
01746 {
01747 cl->query.i_proto = HTTPD_PROTO_RTSP;
01748 }
01749 }
01750 else
01751 {
01752 char *p2;
01753 char *p3;
01754
01755 while( *p == ' ' )
01756 {
01757 p++;
01758 }
01759 p2 = strchr( p, ' ' );
01760 if( p2 )
01761 {
01762 *p2++ = '\0';
01763 }
01764 if( !strncasecmp( p, "rtsp:", 5 ) )
01765 {
01766
01767 p += 5;
01768 while( *p == '/' ) p++;
01769 while( *p && *p != '/' ) p++;
01770 }
01771 cl->query.psz_url = strdup( p );
01772 if( ( p3 = strchr( cl->query.psz_url, '?' ) ) )
01773 {
01774 *p3++ = '\0';
01775 cl->query.psz_args = (uint8_t *)strdup( p3 );
01776 }
01777 if( p2 )
01778 {
01779 while( *p2 == ' ' )
01780 {
01781 p2++;
01782 }
01783 if( !strncasecmp( p2, "HTTP/1.", 7 ) )
01784 {
01785 cl->query.i_proto = HTTPD_PROTO_HTTP;
01786 cl->query.i_version = atoi( p2+7 );
01787 }
01788 else if( !strncasecmp( p2, "RTSP/1.", 7 ) )
01789 {
01790 cl->query.i_proto = HTTPD_PROTO_RTSP;
01791 cl->query.i_version = atoi( p2+7 );
01792 }
01793 }
01794 p = p2;
01795 }
01796 }
01797 if( p )
01798 {
01799 p = strchr( p, '\n' );
01800 }
01801 if( p )
01802 {
01803 while( *p == '\n' || *p == '\r' )
01804 {
01805 p++;
01806 }
01807 while( p && *p != '\0' )
01808 {
01809 char *line = p;
01810 char *eol = p = strchr( p, '\n' );
01811 char *colon;
01812
01813 while( eol && eol >= line && ( *eol == '\n' || *eol == '\r' ) )
01814 {
01815 *eol-- = '\0';
01816 }
01817
01818 if( ( colon = strchr( line, ':' ) ) )
01819 {
01820 char *name;
01821 char *value;
01822
01823 *colon++ = '\0';
01824 while( *colon == ' ' )
01825 {
01826 colon++;
01827 }
01828 name = strdup( line );
01829 value = strdup( colon );
01830
01831 TAB_APPEND( cl->query.i_name, cl->query.name, name );
01832 TAB_APPEND( cl->query.i_value,cl->query.value,value);
01833
01834 if( !strcasecmp( name, "Content-Length" ) )
01835 {
01836 cl->query.i_body = atol( value );
01837 }
01838 }
01839
01840 if( p )
01841 {
01842 p++;
01843 while( *p == '\n' || *p == '\r' )
01844 {
01845 p++;
01846 }
01847 }
01848 }
01849 }
01850 if( cl->query.i_body > 0 )
01851 {
01852
01853
01854 cl->query.p_body = malloc( cl->query.i_body );
01855 cl->i_buffer = 0;
01856 }
01857 else
01858 {
01859 cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
01860 }
01861 }
01862 }
01863 }
01864
01865
01866 #if defined( WIN32 ) || defined( UNDER_CE )
01867 if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
01868 #else
01869 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
01870 #endif
01871 {
01872 if( cl->query.i_proto != HTTPD_PROTO_NONE && cl->query.i_type != HTTPD_MSG_NONE )
01873 {
01874
01875 if( cl->query.i_body > 0 )
01876 {
01877 cl->query.i_body = cl->i_buffer;
01878 }
01879 cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
01880 }
01881 else
01882 {
01883 cl->i_state = HTTPD_CLIENT_DEAD;
01884 }
01885 }
01886 cl->i_activity_date = mdate();
01887
01888
01889 if( cl->query.i_proto == HTTPD_PROTO_RTSP )
01890 cl->i_activity_timeout = 0;
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917 }
01918
01919
01920 static void httpd_ClientSend( httpd_client_t *cl )
01921 {
01922 int i;
01923 int i_len;
01924
01925 if( cl->i_buffer < 0 )
01926 {
01927
01928 int i_size = 0;
01929 char *p;
01930
01931 i_size = strlen( "HTTP/1.") + 10 + 10 +
01932 strlen( cl->answer.psz_status ? cl->answer.psz_status : "" ) + 5;
01933 for( i = 0; i < cl->answer.i_name; i++ )
01934 {
01935 i_size += strlen( cl->answer.name[i] ) + 2 +
01936 strlen( cl->answer.value[i] ) + 2;
01937 }
01938
01939 if( cl->i_buffer_size < i_size )
01940 {
01941 cl->i_buffer_size = i_size;
01942 free( cl->p_buffer );
01943 cl->p_buffer = malloc( i_size );
01944 }
01945 p = (char *)cl->p_buffer;
01946
01947 p += sprintf( p, "%s/1.%d %d %s\r\n",
01948 cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP",
01949 cl->answer.i_version,
01950 cl->answer.i_status, cl->answer.psz_status );
01951 for( i = 0; i < cl->answer.i_name; i++ )
01952 {
01953 p += sprintf( p, "%s: %s\r\n", cl->answer.name[i],
01954 cl->answer.value[i] );
01955 }
01956 p += sprintf( p, "\r\n" );
01957
01958 cl->i_buffer = 0;
01959 cl->i_buffer_size = (uint8_t*)p - cl->p_buffer;
01960
01961
01962
01963 }
01964
01965 i_len = httpd_NetSend( cl, &cl->p_buffer[cl->i_buffer],
01966 cl->i_buffer_size - cl->i_buffer );
01967 if( i_len >= 0 )
01968 {
01969 cl->i_activity_date = mdate();
01970 cl->i_buffer += i_len;
01971
01972 if( cl->i_buffer >= cl->i_buffer_size )
01973 {
01974 if( cl->answer.i_body == 0 && cl->answer.i_body_offset > 0 &&
01975 !cl->b_read_waiting )
01976 {
01977
01978 int i_msg = cl->query.i_type;
01979 int64_t i_offset = cl->answer.i_body_offset;
01980
01981 httpd_MsgClean( &cl->answer );
01982 cl->answer.i_body_offset = i_offset;
01983
01984 cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
01985 &cl->answer, &cl->query );
01986 }
01987
01988 if( cl->answer.i_body > 0 )
01989 {
01990
01991 free( cl->p_buffer );
01992 cl->p_buffer = cl->answer.p_body;
01993 cl->i_buffer_size = cl->answer.i_body;
01994 cl->i_buffer = 0;
01995
01996 cl->answer.i_body = 0;
01997 cl->answer.p_body = NULL;
01998 }
01999 else
02000 {
02001
02002 cl->i_state = HTTPD_CLIENT_SEND_DONE;
02003 }
02004 }
02005 }
02006 else
02007 {
02008 #if defined( WIN32 ) || defined( UNDER_CE )
02009 if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
02010 #else
02011 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
02012 #endif
02013 {
02014
02015 cl->i_state = HTTPD_CLIENT_DEAD;
02016 }
02017 }
02018 }
02019
02020 static void httpd_ClientTlsHsIn( httpd_client_t *cl )
02021 {
02022 switch( tls_SessionContinueHandshake( cl->p_tls ) )
02023 {
02024 case 0:
02025 cl->i_state = HTTPD_CLIENT_RECEIVING;
02026 break;
02027
02028 case -1:
02029 cl->i_state = HTTPD_CLIENT_DEAD;
02030 cl->p_tls = NULL;
02031 break;
02032
02033 case 2:
02034 cl->i_state = HTTPD_CLIENT_TLS_HS_OUT;
02035 }
02036 }
02037
02038 static void httpd_ClientTlsHsOut( httpd_client_t *cl )
02039 {
02040 switch( tls_SessionContinueHandshake( cl->p_tls ) )
02041 {
02042 case 0:
02043 cl->i_state = HTTPD_CLIENT_RECEIVING;
02044 break;
02045
02046 case -1:
02047 cl->i_state = HTTPD_CLIENT_DEAD;
02048 cl->p_tls = NULL;
02049 break;
02050
02051 case 1:
02052 cl->i_state = HTTPD_CLIENT_TLS_HS_IN;
02053 break;
02054 }
02055 }
02056
02057 static void httpd_HostThread( httpd_host_t *host )
02058 {
02059 tls_session_t *p_tls = NULL;
02060
02061 while( !host->b_die )
02062 {
02063 struct timeval timeout;
02064 fd_set fds_read;
02065 fd_set fds_write;
02066
02067 int fd, i_fd;
02068 int i_handle_max = 0;
02069 int i_ret;
02070 int i_client;
02071 int b_low_delay = 0;
02072
02073 if( host->i_url <= 0 )
02074 {
02075
02076 msleep( 200000 );
02077 continue;
02078 }
02079
02080
02081 FD_ZERO( &fds_read );
02082 FD_ZERO( &fds_write );
02083
02084 i_handle_max = -1;
02085
02086 for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ )
02087 {
02088 FD_SET( fd, &fds_read );
02089 if( fd > i_handle_max )
02090 i_handle_max = fd;
02091 }
02092
02093
02094 if( ( p_tls == NULL ) && ( host->p_tls != NULL ) )
02095 p_tls = tls_ServerSessionPrepare( host->p_tls );
02096
02097
02098 vlc_mutex_lock( &host->lock );
02099 for( i_client = 0; i_client < host->i_client; i_client++ )
02100 {
02101 httpd_client_t *cl = host->client[i_client];
02102
02103 if( cl->i_ref < 0 || ( cl->i_ref == 0 &&
02104 ( cl->i_state == HTTPD_CLIENT_DEAD ||
02105 ( cl->i_activity_timeout > 0 &&
02106 cl->i_activity_date+cl->i_activity_timeout < mdate()) ) ) )
02107 {
02108 httpd_ClientClean( cl );
02109 TAB_REMOVE( host->i_client, host->client, cl );
02110 free( cl );
02111 i_client--;
02112 continue;
02113 }
02114 else if( ( cl->i_state == HTTPD_CLIENT_RECEIVING )
02115 || ( cl->i_state == HTTPD_CLIENT_TLS_HS_IN ) )
02116 {
02117 FD_SET( cl->fd, &fds_read );
02118 i_handle_max = __MAX( i_handle_max, cl->fd );
02119 }
02120 else if( ( cl->i_state == HTTPD_CLIENT_SENDING )
02121 || ( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT ) )
02122 {
02123 FD_SET( cl->fd, &fds_write );
02124 i_handle_max = __MAX( i_handle_max, cl->fd );
02125 }
02126 else if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE )
02127 {
02128 httpd_message_t *answer = &cl->answer;
02129 httpd_message_t *query = &cl->query;
02130 int i_msg = query->i_type;
02131
02132 httpd_MsgInit( answer );
02133
02134
02135 if( cl->i_mode != HTTPD_CLIENT_BIDIR &&
02136 (i_msg == HTTPD_MSG_ANSWER || i_msg == HTTPD_MSG_CHANNEL) )
02137 {
02138
02139
02140 cl->url = NULL;
02141 cl->i_state = HTTPD_CLIENT_DEAD;
02142 }
02143 else if( i_msg == HTTPD_MSG_ANSWER )
02144 {
02145
02146
02147 if( cl->url && cl->url->catch[i_msg].cb )
02148 {
02149 cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys,
02150 cl, NULL, query );
02151 }
02152 cl->i_state = HTTPD_CLIENT_WAITING;
02153 }
02154 else if( i_msg == HTTPD_MSG_CHANNEL )
02155 {
02156
02157
02158 if( cl->url && cl->url->catch[i_msg].cb )
02159 {
02160 cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys,
02161 cl, NULL, query );
02162 }
02163 cl->i_state = HTTPD_CLIENT_WAITING;
02164 }
02165 else if( i_msg == HTTPD_MSG_OPTIONS )
02166 {
02167 int i_cseq;
02168
02169
02170 answer->i_proto = query->i_proto ;
02171 answer->i_type = HTTPD_MSG_ANSWER;
02172 answer->i_version= 0;
02173 answer->i_status = 200;
02174 answer->psz_status = strdup( "Ok" );
02175
02176 answer->i_body = 0;
02177 answer->p_body = NULL;
02178
02179 i_cseq = atoi( httpd_MsgGet( query, "Cseq" ) );
02180 httpd_MsgAdd( answer, "Cseq", "%d", i_cseq );
02181 httpd_MsgAdd( answer, "Server", "VLC Server" );
02182 httpd_MsgAdd( answer, "Public", "DESCRIBE, SETUP, "
02183 "TEARDOWN, PLAY, PAUSE" );
02184 httpd_MsgAdd( answer, "Content-Length", "%d",
02185 answer->i_body );
02186
02187 cl->i_buffer = -1;
02188
02189 cl->i_state = HTTPD_CLIENT_SENDING;
02190 }
02191 else if( i_msg == HTTPD_MSG_NONE )
02192 {
02193 if( query->i_proto == HTTPD_PROTO_NONE )
02194 {
02195 cl->url = NULL;
02196 cl->i_state = HTTPD_CLIENT_DEAD;
02197 }
02198 else
02199 {
02200 uint8_t *p;
02201
02202
02203 answer->i_proto = query->i_proto ;
02204 answer->i_type = HTTPD_MSG_ANSWER;
02205 answer->i_version= 0;
02206 answer->i_status = 501;
02207 answer->psz_status = strdup( "Unimplemented" );
02208
02209 p = answer->p_body = malloc( 1000 );
02210
02211 p += sprintf( (char *)p,
02212 "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02213 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
02214 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02215 "<html>\n"
02216 "<head>\n"
02217 "<title>Error 501</title>\n"
02218 "</head>\n"
02219 "<body>\n"
02220 "<h1>501 Unimplemented</h1>\n"
02221 "<hr />\n"
02222 "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02223 "</body>\n"
02224 "</html>\n" );
02225
02226 answer->i_body = p - answer->p_body;
02227 httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
02228
02229 cl->i_buffer = -1;
02230 cl->i_state = HTTPD_CLIENT_SENDING;
02231 }
02232 }
02233 else
02234 {
02235 vlc_bool_t b_auth_failed = VLC_FALSE;
02236 vlc_bool_t b_hosts_failed = VLC_FALSE;
02237 int i;
02238
02239
02240 for( i = 0; i < host->i_url; i++ )
02241 {
02242 httpd_url_t *url = host->url[i];
02243
02244 if( !strcmp( url->psz_url, query->psz_url ) )
02245 {
02246 if( url->catch[i_msg].cb )
02247 {
02248 if( answer && ( url->p_acl != NULL ) )
02249 {
02250 char ip[NI_MAXNUMERICHOST];
02251
02252 if( httpd_ClientIP( cl, ip ) != NULL )
02253 {
02254 if( ACL_Check( url->p_acl, ip ) )
02255 {
02256 b_hosts_failed = VLC_TRUE;
02257 break;
02258 }
02259 }
02260 else
02261 b_hosts_failed = VLC_TRUE;
02262 }
02263
02264 if( answer && ( *url->psz_user || *url->psz_password ) )
02265 {
02266
02267 char *b64 = httpd_MsgGet( query, "Authorization" );
02268 char *auth;
02269 char *id;
02270
02271 asprintf( &id, "%s:%s", url->psz_user, url->psz_password );
02272 auth = malloc( strlen(b64) + 1 );
02273
02274 if( !strncasecmp( b64, "BASIC", 5 ) )
02275 {
02276 b64 += 5;
02277 while( *b64 == ' ' )
02278 {
02279 b64++;
02280 }
02281 b64_decode( auth, b64 );
02282 }
02283 else
02284 {
02285 strcpy( auth, "" );
02286 }
02287 if( strcmp( id, auth ) )
02288 {
02289 httpd_MsgAdd( answer, "WWW-Authenticate", "Basic realm=\"%s\"", url->psz_user );
02290
02291 b_auth_failed = VLC_TRUE;
02292 free( id );
02293 free( auth );
02294 break;
02295 }
02296
02297 free( id );
02298 free( auth );
02299 }
02300
02301 if( !url->catch[i_msg].cb( url->catch[i_msg].p_sys, cl, answer, query ) )
02302 {
02303 if( answer->i_proto == HTTPD_PROTO_NONE )
02304 {
02305
02306 cl->i_buffer = cl->i_buffer_size;
02307 }
02308 else
02309 cl->i_buffer = -1;
02310
02311
02312 answer = NULL;
02313 if( cl->url == NULL )
02314 {
02315 cl->url = url;
02316 }
02317 }
02318 }
02319 }
02320 }
02321 if( answer )
02322 {
02323 uint8_t *p;
02324
02325 answer->i_proto = query->i_proto;
02326 answer->i_type = HTTPD_MSG_ANSWER;
02327 answer->i_version= 0;
02328 p = answer->p_body = malloc( 1000 + strlen(query->psz_url) );
02329
02330 if( b_hosts_failed )
02331 {
02332 answer->i_status = 403;
02333 answer->psz_status = strdup( "Forbidden" );
02334
02335
02336 p += sprintf( (char *)p,
02337 "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02338 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
02339 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02340 "<html>\n"
02341 "<head>\n"
02342 "<title>Error 403</title>\n"
02343 "</head>\n"
02344 "<body>\n"
02345 "<h1>403 Forbidden (%s)</h1>\n"
02346 "<hr />\n"
02347 "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02348 "</body>\n"
02349 "</html>\n", query->psz_url );
02350 }
02351 else if( b_auth_failed )
02352 {
02353 answer->i_status = 401;
02354 answer->psz_status = strdup( "Authorization Required" );
02355
02356 p += sprintf( (char *)p,
02357 "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02358 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
02359 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02360 "<html>\n"
02361 "<head>\n"
02362 "<title>Error 401</title>\n"
02363 "</head>\n"
02364 "<body>\n"
02365 "<h1>401 Authorization Required (%s)</h1>\n"
02366 "<hr />\n"
02367 "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02368 "</body>\n"
02369 "</html>\n", query->psz_url );
02370 }
02371 else
02372 {
02373
02374 answer->i_status = 404;
02375 answer->psz_status = strdup( "Not found" );
02376
02377 p += sprintf( (char *)p,
02378 "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02379 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
02380 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02381 "<html>\n"
02382 "<head>\n"
02383 "<title>Error 404</title>\n"
02384 "</head>\n"
02385 "<body>\n"
02386 "<h1>404 Resource not found(%s)</h1>\n"
02387 "<hr />\n"
02388 "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02389 "</body>\n"
02390 "</html>\n", query->psz_url );
02391 }
02392
02393 answer->i_body = p - answer->p_body;
02394 cl->i_buffer = -1;
02395 httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
02396 }
02397
02398 cl->i_state = HTTPD_CLIENT_SENDING;
02399 }
02400 }
02401 else if( cl->i_state == HTTPD_CLIENT_SEND_DONE )
02402 {
02403 if( cl->i_mode == HTTPD_CLIENT_FILE || cl->answer.i_body_offset == 0 )
02404 {
02405 cl->url = NULL;
02406 if( ( cl->query.i_proto == HTTPD_PROTO_HTTP &&
02407 ( ( cl->answer.i_version == 0 && !strcasecmp( httpd_MsgGet( &cl->answer, "Connection" ), "Keep-Alive" ) ) ||
02408 ( cl->answer.i_version == 1 && strcasecmp( httpd_MsgGet( &cl->answer, "Connection" ), "Close" ) ) ) ) ||
02409 ( cl->query.i_proto == HTTPD_PROTO_RTSP &&
02410 strcasecmp( httpd_MsgGet( &cl->query, "Connection" ), "Close" ) &&
02411 strcasecmp( httpd_MsgGet( &cl->answer, "Connection" ), "Close" ) ) )
02412 {
02413 httpd_MsgClean( &cl->query );
02414 httpd_MsgInit( &cl->query );
02415
02416 cl->i_buffer = 0;
02417 cl->i_buffer_size = 1000;
02418 free( cl->p_buffer );
02419 cl->p_buffer = malloc( cl->i_buffer_size );
02420 cl->i_state = HTTPD_CLIENT_RECEIVING;
02421 }
02422 else
02423 {
02424 cl->i_state = HTTPD_CLIENT_DEAD;
02425 }
02426 httpd_MsgClean( &cl->answer );
02427 }
02428 else if( cl->b_read_waiting )
02429 {
02430
02431 httpd_MsgClean( &cl->answer );
02432 httpd_MsgClean( &cl->query );
02433
02434 cl->i_buffer = 0;
02435 cl->i_buffer_size = 1000;
02436 free( cl->p_buffer );
02437 cl->p_buffer = malloc( cl->i_buffer_size );
02438 cl->i_state = HTTPD_CLIENT_RECEIVING;
02439 cl->b_read_waiting = VLC_FALSE;
02440 }
02441 else
02442 {
02443 int64_t i_offset = cl->answer.i_body_offset;
02444 httpd_MsgClean( &cl->answer );
02445
02446 cl->answer.i_body_offset = i_offset;
02447 free( cl->p_buffer );
02448 cl->p_buffer = NULL;
02449 cl->i_buffer = 0;
02450 cl->i_buffer_size = 0;
02451
02452 cl->i_state = HTTPD_CLIENT_WAITING;
02453 }
02454 }
02455 else if( cl->i_state == HTTPD_CLIENT_WAITING )
02456 {
02457 int64_t i_offset = cl->answer.i_body_offset;
02458 int i_msg = cl->query.i_type;
02459
02460 httpd_MsgInit( &cl->answer );
02461 cl->answer.i_body_offset = i_offset;
02462
02463 cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
02464 &cl->answer, &cl->query );
02465 if( cl->answer.i_type != HTTPD_MSG_NONE )
02466 {
02467
02468 cl->i_buffer = 0;
02469 cl->p_buffer = cl->answer.p_body;
02470 cl->i_buffer_size = cl->answer.i_body;
02471 cl->answer.p_body = NULL;
02472 cl->answer.i_body = 0;
02473 cl->i_state = HTTPD_CLIENT_SENDING;
02474 }
02475 else
02476 {
02477
02478 b_low_delay = VLC_TRUE;
02479 }
02480 }
02481
02482
02483 if( cl->i_mode == HTTPD_CLIENT_BIDIR &&
02484 cl->i_state == HTTPD_CLIENT_SENDING )
02485 {
02486 FD_SET( cl->fd, &fds_read );
02487 i_handle_max = __MAX( i_handle_max, cl->fd );
02488 }
02489 }
02490 vlc_mutex_unlock( &host->lock );
02491
02492
02493 timeout.tv_sec = 0;
02494 timeout.tv_usec = b_low_delay ? 20000 : 100000;
02495
02496 i_ret = select( i_handle_max + 1,
02497 &fds_read, &fds_write, NULL, &timeout );
02498
02499 if( i_ret == -1 && errno != EINTR )
02500 {
02501 #if defined(WIN32) || defined(UNDER_CE)
02502 msg_Warn( host, "cannot select sockets (%d)", WSAGetLastError( ) );
02503 #else
02504 msg_Warn( host, "cannot select sockets : %s", strerror( errno ) );
02505 #endif
02506 msleep( 1000 );
02507 continue;
02508 }
02509 else if( i_ret <= 0 )
02510 {
02511 continue;
02512 }
02513
02514
02515 for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ )
02516 {
02517 if( FD_ISSET( fd, &fds_read ) )
02518 {
02519 socklen_t i_sock_size = sizeof( struct sockaddr_storage );
02520 struct sockaddr_storage sock;
02521
02522 fd = accept( fd, (struct sockaddr *)&sock, &i_sock_size );
02523 if( fd >= 0 )
02524 {
02525 int i_state = 0;
02526
02527
02528 #if defined( WIN32 ) || defined( UNDER_CE )
02529 {
02530 unsigned long i_dummy = 1;
02531 ioctlsocket( fd, FIONBIO, &i_dummy );
02532 }
02533 #else
02534 fcntl( fd, F_SETFL, O_NONBLOCK );
02535 #endif
02536
02537 if( p_tls != NULL)
02538 {
02539 switch ( tls_ServerSessionHandshake( p_tls, fd ) )
02540 {
02541 case -1:
02542 msg_Err( host, "Rejecting TLS connection" );
02543 net_Close( fd );
02544 fd = -1;
02545 p_tls = NULL;
02546 break;
02547
02548 case 1:
02549 i_state = HTTPD_CLIENT_TLS_HS_IN;
02550 break;
02551
02552 case 2:
02553 i_state = HTTPD_CLIENT_TLS_HS_OUT;
02554 break;
02555 }
02556 }
02557
02558 if( fd >= 0 )
02559 {
02560 httpd_client_t *cl;
02561
02562 cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls );
02563 p_tls = NULL;
02564 vlc_mutex_lock( &host->lock );
02565 TAB_APPEND( host->i_client, host->client, cl );
02566 vlc_mutex_unlock( &host->lock );
02567
02568 if( i_state != 0 )
02569 cl->i_state = i_state;
02570 }
02571 }
02572 }
02573 }
02574
02575
02576 vlc_mutex_lock( &host->lock );
02577 for( i_client = 0; i_client < host->i_client; i_client++ )
02578 {
02579 httpd_client_t *cl = host->client[i_client];
02580 if( cl->i_state == HTTPD_CLIENT_RECEIVING )
02581 {
02582 httpd_ClientRecv( cl );
02583 }
02584 else if( cl->i_state == HTTPD_CLIENT_SENDING )
02585 {
02586 httpd_ClientSend( cl );
02587 }
02588 else if( cl->i_state == HTTPD_CLIENT_TLS_HS_IN )
02589 {
02590 httpd_ClientTlsHsIn( cl );
02591 }
02592 else if( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT )
02593 {
02594 httpd_ClientTlsHsOut( cl );
02595 }
02596
02597 if( cl->i_mode == HTTPD_CLIENT_BIDIR &&
02598 cl->i_state == HTTPD_CLIENT_SENDING &&
02599 FD_ISSET( cl->fd, &fds_read ) )
02600 {
02601 cl->b_read_waiting = VLC_TRUE;
02602 }
02603 }
02604 vlc_mutex_unlock( &host->lock );
02605 }
02606
02607 if( p_tls != NULL )
02608 tls_ServerSessionClose( p_tls );
02609 }
02610
02611 #else
02612
02613
02614 httpd_host_t *httpd_TLSHostNew( vlc_object_t *a, char *b, int c,
02615 tls_server_t *d )
02616 {
02617 msg_Err( a, "HTTP daemon support is disabled" );
02618 return 0;
02619 }
02620 httpd_host_t *httpd_HostNew( vlc_object_t *a, char *b, int c )
02621 {
02622 msg_Err( a, "HTTP daemon support is disabled" );
02623 return 0;
02624 }
02625 void httpd_HostDelete( httpd_host_t *a )
02626 {
02627 }
02628 httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url,
02629 char *psz_user, char *psz_password,
02630 const vlc_acl_t *p_acl )
02631 {
02632 return NULL;
02633 }
02634 httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url,
02635 char *psz_user, char *psz_password,
02636 const vlc_acl_t *p_acl )
02637 {
02638 return NULL;
02639 }
02640 int httpd_UrlCatch( httpd_url_t *a, int b, httpd_callback_t c,
02641 httpd_callback_sys_t *d ){ return 0; }
02642 void httpd_UrlDelete( httpd_url_t *a ){}
02643
02644 char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip ) { return NULL; }
02645 char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip ) { return NULL; }
02646
02647 void httpd_ClientModeStream( httpd_client_t *a ){}
02648 void httpd_ClientModeBidir( httpd_client_t *a ){}
02649
02650 void httpd_FileDelete( httpd_file_t *a ){}
02651 httpd_file_t *httpd_FileNew( httpd_host_t *a, char *b, char *c, char *d,
02652 char *e, httpd_file_callback_t f,
02653 httpd_file_sys_t *g ){ return 0; }
02654
02655 httpd_handler_t *httpd_HandlerNew( httpd_host_t *host, const char *psz_url,
02656 const char *psz_user,
02657 const char *psz_password,
02658 const vlc_acl_t *p_acl,
02659 httpd_handler_callback_t pf_fill,
02660 httpd_handler_sys_t *p_sys )
02661 {
02662 return NULL;
02663 }
02664 void httpd_HandlerDelete( httpd_handler_t *handler ) {}
02665
02666 void httpd_RedirectDelete( httpd_redirect_t *a ){}
02667 httpd_redirect_t *httpd_RedirectNew( httpd_host_t *a,
02668 char *b, char *c ){ return 0; }
02669
02670 void httpd_StreamDelete( httpd_stream_t *a ){}
02671 int httpd_StreamHeader( httpd_stream_t *a, uint8_t *b, int c ){ return 0; }
02672 int httpd_StreamSend ( httpd_stream_t *a, uint8_t *b, int c ){ return 0; }
02673 httpd_stream_t *httpd_StreamNew( httpd_host_t *a, char *b, char *c,
02674 char *d, char *e ){ return 0; }
02675
02676 void httpd_MsgInit ( httpd_message_t *a ){}
02677 void httpd_MsgAdd ( httpd_message_t *a, char *b, char *c, ... ){}
02678 char *httpd_MsgGet ( httpd_message_t *a, char *b ){ return 0; }
02679 void httpd_MsgClean( httpd_message_t *a ){}
02680
02681 #endif