]> git.sesse.net Git - vlc/blob - modules/misc/httpd.c
666800367821d1a0f4b0aa9c21ad89bb1dd30095
[vlc] / modules / misc / httpd.c
1 /*****************************************************************************
2  * httpd.c
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id: httpd.c,v 1.27 2003/08/26 00:40:27 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *
27  * TODO:
28  *  - make that two distinct host:port use different daemon
29  *****************************************************************************/
30 #include <stdlib.h>
31 #include <vlc/vlc.h>
32
33 #include <sys/stat.h>
34
35 #include <errno.h>
36 #include <fcntl.h>
37
38 #include "httpd.h"
39
40 #ifdef HAVE_SYS_TIME_H
41 #    include <sys/time.h>
42 #endif
43
44 #ifdef HAVE_UNISTD_H
45 #   include <unistd.h>
46 #endif
47
48 #if defined( UNDER_CE )
49 #   include <winsock.h>
50 #elif defined( WIN32 )
51 #   include <winsock2.h>
52 #   include <ws2tcpip.h>
53 #   ifndef IN_MULTICAST
54 #       define IN_MULTICAST(a) IN_CLASSD(a)
55 #   endif
56 #else
57 #   include <netdb.h>                                         /* hostent ... */
58 #   include <sys/socket.h>
59 #   include <netinet/in.h>
60 #   ifdef HAVE_ARPA_INET_H
61 #       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
62 #   endif
63 #endif
64
65 #include "network.h"
66
67 #ifndef INADDR_ANY
68 #   define INADDR_ANY  0x00000000
69 #endif
70 #ifndef INADDR_NONE
71 #   define INADDR_NONE 0xFFFFFFFF
72 #endif
73
74 #define LISTEN_BACKLOG          100
75 #define HTTPD_MAX_CONNECTION    512
76 #define HTTPD_CONNECTION_MAX_UNUSED 10000000
77
78
79 #define FREE( p ) if( p ) { free( p); (p) = NULL; }
80
81 #if defined( WIN32 ) || defined( UNDER_CE )
82 #define SOCKET_CLOSE(a)    closesocket(a)
83 #else
84 #define SOCKET_CLOSE(a)    close(a)
85 #endif
86
87 /*****************************************************************************
88  * Exported prototypes
89  *****************************************************************************/
90 static int              Open   ( vlc_object_t * );
91 static void             Close  ( vlc_object_t * );
92
93 /*****************************************************************************
94  * Module descriptor
95  *****************************************************************************/
96 vlc_module_begin();
97     set_description( _("HTTP 1.0 daemon") );
98     set_capability( "httpd", 42 );
99     set_callbacks( Open, Close );
100     var_Create( p_module->p_libvlc, "httpd", VLC_VAR_MUTEX );
101 vlc_module_end();
102
103 /*****************************************************************************
104  * Prototypes
105  *****************************************************************************/
106 static httpd_host_t     *RegisterHost   ( httpd_t *, char *, int );
107 static void             UnregisterHost  ( httpd_t *, httpd_host_t * );
108
109 static httpd_file_t     *RegisterFile   ( httpd_t *,
110                                           char *psz_file, char *psz_mime,
111                                           char *psz_user, char *psz_password,
112                                           httpd_file_callback pf_get,
113                                           httpd_file_callback pf_post,
114                                           httpd_file_callback_args_t *p_args );
115 static void             UnregisterFile  ( httpd_t *, httpd_file_t * );
116
117 //#define httpd_stream_t              httpd_file_t
118 static httpd_stream_t   *RegisterStream ( httpd_t *,
119                                          char *psz_file, char *psz_mime,
120                                          char *psz_user, char *psz_password );
121 static int              SendStream      ( httpd_t *, httpd_stream_t *, uint8_t *, int );
122 static int              HeaderStream    ( httpd_t *, httpd_stream_t *, uint8_t *, int );
123 static void             UnregisterStream( httpd_t *, httpd_stream_t* );
124 static int              Control         ( httpd_t *, int , void*, void* );
125 /*****************************************************************************
126  * Internal definitions
127  *****************************************************************************/
128 struct httpd_host_t
129 {
130     int    i_ref;
131
132     char   *psz_host_addr;
133     int    i_port;
134
135     struct sockaddr_in sock;
136     int    fd;
137
138 };
139
140 enum httpd_authenticate_e
141 {
142     HTTPD_AUTHENTICATE_NONE = 0,
143     HTTPD_AUTHENTICATE_BASIC = 1
144 };
145
146 //typedef httpd_file_t httpd_stream_t;
147
148 struct httpd_file_t
149 {
150     int         i_ref;
151
152     char        *psz_file;
153     char        *psz_mime;
154
155
156     int         i_authenticate_method;
157         char        *psz_user;          /* NULL if no auth */
158         char        *psz_password;      /* NULL if no auth */
159
160     vlc_bool_t  b_stream;               /* if false: httpd will retreive data by a callback
161                                               true:  it's up to the program to give data to httpd */
162     void                *p_sys;         /* provided for user */
163     httpd_file_callback pf_get;         /* it should allocate and fill *pp_data and *pi_data */
164     httpd_file_callback pf_post;        /* it should allocate and fill *pp_data and *pi_data */
165
166     /* private */
167
168     /* circular buffer for stream only */
169     int         i_buffer_size;      /* buffer size, can't be reallocated smaller */
170     uint8_t     *p_buffer;          /* buffer */
171     int64_t     i_buffer_pos;       /* absolute position from begining */
172     int         i_buffer_last_pos;  /* a new connection will start with that */
173
174     /* data to be send at connection time (if any) */
175     int         i_header_size;
176     uint8_t     *p_header;
177 };
178
179
180 enum httpd_connection_state_e
181 {
182     HTTPD_CONNECTION_RECEIVING_REQUEST = 1,
183     HTTPD_CONNECTION_SENDING_HEADER = 2,
184     HTTPD_CONNECTION_SENDING_FILE = 3,
185     HTTPD_CONNECTION_SENDING_STREAM = 4,
186     HTTPD_CONNECTION_TO_BE_CLOSED = 5
187 };
188
189 enum httpd_connection_method_e
190 {
191     HTTPD_CONNECTION_METHOD_GET     = 1,
192     HTTPD_CONNECTION_METHOD_POST    = 2,
193     HTTPD_CONNECTION_METHOD_HEAD    = 3,
194     /* cludgy, only used when parsing connection request */
195     HTTPD_CONNECTION_METHOD_ASFHEAD = 4
196 };
197
198 typedef struct httpd_connection_s
199 {
200     struct httpd_connection_s *p_next;
201     struct httpd_connection_s *p_prev;
202
203     struct  sockaddr_in sock;
204     int     fd;
205     mtime_t i_last_activity_date;
206
207     int    i_state;
208     int    i_method;       /* get/post */
209
210     char    *psz_file;      // file to be send
211     int     i_http_error;   // error to be send with the file
212     char    *psz_user;      // if Authorization in the request header
213     char    *psz_password;
214
215     uint8_t *p_request;     // whith get: ?<*>, with post: main data
216     int      i_request_size;
217
218     httpd_file_t    *p_file;
219
220     /* used while sending header and file */
221     int     i_buffer_size;
222     uint8_t *p_buffer;
223     int     i_buffer;            /* private */
224
225     /* used for stream */
226     int64_t i_stream_pos;   /* absolute pos in stream */
227 } httpd_connection_t;
228
229 /* Linked List of banned IP */
230 typedef struct httpd_banned_ip_s
231 {
232     struct httpd_banned_ip_s *p_next;
233     struct httpd_banned_ip_s *p_prev;
234
235     char *psz_ip;
236
237 } httpd_banned_ip_t;
238 /*
239  * The httpd thread
240  */
241 struct httpd_sys_t
242 {
243     VLC_COMMON_MEMBERS
244
245     vlc_mutex_t             host_lock;
246     volatile int            i_host_count;
247     httpd_host_t            **host;
248
249     vlc_mutex_t             file_lock;
250     int                     i_file_count;
251     httpd_file_t            **file;
252
253     vlc_mutex_t             connection_lock;
254     int                     i_connection_count;
255     httpd_connection_t      *p_first_connection;
256
257     vlc_mutex_t             ban_lock;
258     int                     i_banned_ip_count;
259     httpd_banned_ip_t       *p_first_banned_ip;
260 };
261
262 static void httpd_Thread( httpd_sys_t *p_httpt );
263 static void httpd_ConnnectionNew( httpd_sys_t *, int , struct sockaddr_in * );
264 static void httpd_ConnnectionClose( httpd_sys_t *, httpd_connection_t * );
265 static int httpd_UnbanIP( httpd_sys_t *, httpd_banned_ip_t *);
266 #if 0
267 static int httpd_BanIP( httpd_sys_t *, char *);
268 #endif
269 static httpd_banned_ip_t *httpd_GetbannedIP( httpd_sys_t *, char * );
270
271 /*****************************************************************************
272  * Open:
273  *****************************************************************************/
274
275 static int Open( vlc_object_t *p_this )
276 {
277     httpd_t     *p_httpd = (httpd_t*)p_this;
278     httpd_sys_t *p_httpt;
279
280     /* Launch httpt thread */
281     if( !( p_httpt = vlc_object_create( p_this, sizeof( httpd_sys_t ) ) ) )
282     {
283         msg_Err( p_this, "out of memory" );
284         return( VLC_EGENERIC );
285     }
286
287     p_httpt->b_die  = 0;
288     p_httpt->b_error= 0;
289
290     /* init httpt_t structure */
291     vlc_mutex_init( p_httpd, &p_httpt->host_lock );
292     p_httpt->i_host_count = 0;
293     p_httpt->host = NULL;
294
295     vlc_mutex_init( p_httpd, &p_httpt->file_lock );
296     p_httpt->i_file_count = 0;
297     p_httpt->file = NULL;
298
299     vlc_mutex_init( p_httpd, &p_httpt->connection_lock );
300     p_httpt->i_connection_count = 0;
301     p_httpt->p_first_connection = NULL;
302
303     vlc_mutex_init( p_httpd, &p_httpt->ban_lock );
304     p_httpt->i_banned_ip_count = 0;
305     p_httpt->p_first_banned_ip = NULL;
306
307     /* start the thread */
308     if( vlc_thread_create( p_httpt, "httpd thread",
309                            httpd_Thread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
310     {
311         msg_Err( p_this, "cannot spawn http thread" );
312
313         vlc_mutex_destroy( &p_httpt->host_lock );
314         vlc_mutex_destroy( &p_httpt->file_lock );
315         vlc_mutex_destroy( &p_httpt->connection_lock );
316         vlc_mutex_destroy( &p_httpt->ban_lock );
317
318         vlc_object_destroy( p_httpt );
319         return( VLC_EGENERIC );
320     }
321
322     msg_Info( p_httpd, "http thread launched" );
323
324     p_httpd->p_sys = p_httpt;
325     p_httpd->pf_register_host   = RegisterHost;
326     p_httpd->pf_unregister_host = UnregisterHost;
327     p_httpd->pf_register_file   = RegisterFile;
328     p_httpd->pf_unregister_file = UnregisterFile;
329     p_httpd->pf_register_stream = RegisterStream;
330     p_httpd->pf_header_stream   = HeaderStream;
331     p_httpd->pf_send_stream     = SendStream;
332     p_httpd->pf_unregister_stream=UnregisterStream;
333     p_httpd->pf_control         = Control;
334
335     return( VLC_SUCCESS );
336 }
337
338 /*****************************************************************************
339  * Close: close the target
340  *****************************************************************************/
341 static void Close( vlc_object_t * p_this )
342 {
343     httpd_t     *p_httpd = (httpd_t*)p_this;
344     httpd_sys_t *p_httpt = p_httpd->p_sys;
345
346     httpd_connection_t *p_con;
347     httpd_banned_ip_t *p_banned_ip;
348
349     int i;
350
351     p_httpt->b_die = 1;
352     vlc_thread_join( p_httpt );
353
354     /* first close all host */
355     vlc_mutex_destroy( &p_httpt->host_lock );
356     if( p_httpt->i_host_count )
357     {
358         msg_Err( p_httpd, "still have %d hosts registered !", p_httpt->i_host_count );
359     }
360     for( i = 0; i < p_httpt->i_host_count; i++ )
361     {
362 #define p_host p_httpt->host[i]
363         FREE( p_host->psz_host_addr );
364         SOCKET_CLOSE( p_host->fd );
365
366         FREE( p_host );
367 #undef p_host
368     }
369     FREE( p_httpt->host );
370
371     /* now all file */
372     vlc_mutex_destroy( &p_httpt->file_lock );
373     if( p_httpt->i_file_count )
374     {
375         msg_Err( p_httpd, "still have %d files registered !", p_httpt->i_file_count );
376     }
377     for( i = 0; i < p_httpt->i_file_count; i++ )
378     {
379 #define p_file p_httpt->file[i]
380         FREE( p_file->psz_file );
381         FREE( p_file->psz_mime );
382         if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
383         {
384             FREE( p_file->psz_user );
385             FREE( p_file->psz_password );
386         }
387         FREE( p_file->p_buffer );
388
389         FREE( p_file );
390 #undef p_file
391     }
392     FREE( p_httpt->file );
393
394     /* andd close all connection */
395     vlc_mutex_destroy( &p_httpt->connection_lock );
396     if( p_httpt->i_connection_count )
397     {
398         msg_Warn( p_httpd, "%d connections still in use", p_httpt->i_connection_count );
399     }
400     while( ( p_con = p_httpt->p_first_connection ) )
401     {
402         httpd_ConnnectionClose( p_httpt, p_con );
403     }
404
405     /* Free all banned IP */
406     vlc_mutex_destroy( &p_httpt->ban_lock );
407     while( ( p_banned_ip = p_httpt->p_first_banned_ip))
408     {
409         httpd_UnbanIP(p_httpt,p_banned_ip);
410     }
411
412     msg_Info( p_httpd, "httpd instance closed" );
413     vlc_object_destroy( p_httpt );
414 }
415
416
417 /****************************************************************************
418  ****************************************************************************
419  ***
420  ***
421  ****************************************************************************
422  ****************************************************************************/
423 static int BuildAddr( struct sockaddr_in * p_socket,
424                       const char * psz_address, int i_port )
425 {
426     /* Reset struct */
427     memset( p_socket, 0, sizeof( struct sockaddr_in ) );
428     p_socket->sin_family = AF_INET;                                /* family */
429     p_socket->sin_port = htons( (uint16_t)i_port );
430     if( !*psz_address )
431     {
432         p_socket->sin_addr.s_addr = INADDR_ANY;
433     }
434     else
435     {
436         struct hostent    * p_hostent;
437
438         /* Try to convert address directly from in_addr - this will work if
439          * psz_address is dotted decimal. */
440 #ifdef HAVE_ARPA_INET_H
441         if( !inet_aton( psz_address, &p_socket->sin_addr ) )
442 #else
443         p_socket->sin_addr.s_addr = inet_addr( psz_address );
444         if( p_socket->sin_addr.s_addr == INADDR_NONE )
445 #endif
446         {
447             /* We have a fqdn, try to find its address */
448             if ( (p_hostent = gethostbyname( psz_address )) == NULL )
449             {
450                 return( -1 );
451             }
452
453             /* Copy the first address of the host in the socket address */
454             memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
455                      p_hostent->h_length );
456         }
457     }
458     return( 0 );
459 }
460
461
462 /*
463  * listen on a host for a httpd instance
464  */
465
466 static httpd_host_t *_RegisterHost( httpd_sys_t *p_httpt, char *psz_host_addr, int i_port )
467 {
468     httpd_host_t    *p_host;
469     struct sockaddr_in  sock;
470     int i;
471     int fd = -1;
472     int i_opt;
473 #if !defined( WIN32 ) && !defined( UNDER_CE )
474     int i_flags;
475 #endif
476
477     if( BuildAddr( &sock, psz_host_addr, i_port ) )
478     {
479         msg_Err( p_httpt, "cannot build address for %s:%d", psz_host_addr, i_port );
480         return NULL;
481     }
482
483     /* is it already declared ? */
484     vlc_mutex_lock( &p_httpt->host_lock );
485     for( i = 0; i < p_httpt->i_host_count; i++ )
486     {
487         if( p_httpt->host[i]->sock.sin_port == sock.sin_port &&
488             ( p_httpt->host[i]->sock.sin_addr.s_addr == INADDR_ANY ||
489             p_httpt->host[i]->sock.sin_addr.s_addr == sock.sin_addr.s_addr ) )
490         {
491             break;
492         }
493     }
494
495     if( i < p_httpt->i_host_count )
496     {
497         /* yes, increment ref count and succed */
498         p_httpt->host[i]->i_ref++;
499         vlc_mutex_unlock( &p_httpt->host_lock );
500         return( p_httpt->host[i] );
501     }
502
503     /* need to add a new listening socket */
504
505     /* open socket */
506     fd = socket( AF_INET, SOCK_STREAM, 0 );
507     if( fd < 0 )
508     {
509         msg_Err( p_httpt, "cannot open socket" );
510         goto socket_failed;
511     }
512     /* reuse socket */
513     i_opt = 1;
514     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
515                     (void *) &i_opt, sizeof( i_opt ) ) < 0 )
516     {
517         msg_Warn( p_httpt, "cannot configure socket (SO_REUSEADDR)" );
518     }
519     /* bind it */
520     if( bind( fd, (struct sockaddr *)&sock, sizeof( struct sockaddr_in ) ) < 0 )
521     {
522         msg_Err( p_httpt, "cannot bind socket" );
523         goto socket_failed;
524     }
525     /* set to non-blocking */
526 #if defined( WIN32 ) || defined( UNDER_CE )
527     {
528         unsigned long i_dummy = 1;
529         if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
530         {
531             msg_Err( p_httpt, "cannot set socket to non-blocking mode" );
532             goto socket_failed;
533         }
534     }
535 #else
536     if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
537     {
538         msg_Err( p_httpt, "cannot F_GETFL socket" );
539         goto socket_failed;
540     }
541     if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
542     {
543         msg_Err( p_httpt, "cannot F_SETFL O_NONBLOCK" );
544         goto socket_failed;
545     }
546 #endif
547     /* listen */
548     if( listen( fd, LISTEN_BACKLOG ) < 0 )
549     {
550         msg_Err( p_httpt, "cannot listen socket" );
551         goto socket_failed;
552     }
553
554     if( p_httpt->host )
555     {
556         p_httpt->host = realloc( p_httpt->host, sizeof( httpd_host_t *)  * ( p_httpt->i_host_count + 1 ) );
557     }
558     else
559     {
560         p_httpt->host = malloc( sizeof( httpd_host_t *) );
561     }
562     p_host                = malloc( sizeof( httpd_host_t ) );
563     p_host->i_ref         = 1;
564     p_host->psz_host_addr = strdup( psz_host_addr );
565     p_host->i_port        = i_port;
566     p_host->sock          = sock;
567     p_host->fd            = fd;
568
569     p_httpt->host[p_httpt->i_host_count++] = p_host;
570     vlc_mutex_unlock( &p_httpt->host_lock );
571
572     return p_host;
573
574 socket_failed:
575     vlc_mutex_unlock( &p_httpt->host_lock );
576     if( fd >= 0 )
577     {
578         SOCKET_CLOSE( fd );
579     }
580     return NULL;
581 }
582 static httpd_host_t     *RegisterHost( httpd_t *p_httpd, char *psz_host_addr, int i_port )
583 {
584     return( _RegisterHost( p_httpd->p_sys, psz_host_addr, i_port ) );
585 }
586
587 /*
588  * remove a listening host for an httpd instance
589  */
590 static void            _UnregisterHost( httpd_sys_t *p_httpt, httpd_host_t *p_host )
591 {
592     int i;
593
594     vlc_mutex_lock( &p_httpt->host_lock );
595     for( i = 0; i < p_httpt->i_host_count; i++ )
596     {
597         if( p_httpt->host[i] == p_host )
598         {
599             break;
600         }
601     }
602     if( i >= p_httpt->i_host_count )
603     {
604         vlc_mutex_unlock( &p_httpt->host_lock );
605         msg_Err( p_httpt, "cannot unregister host" );
606         return;
607     }
608
609     p_host->i_ref--;
610
611     if( p_host->i_ref > 0 )
612     {
613         /* still in use */
614         vlc_mutex_unlock( &p_httpt->host_lock );
615         return;
616     }
617
618     /* no more used */
619     FREE( p_host->psz_host_addr );
620     SOCKET_CLOSE( p_host->fd );
621
622     FREE( p_host );
623
624     if( p_httpt->i_host_count <= 1 )
625     {
626         FREE( p_httpt->host );
627         p_httpt->i_host_count = 0;
628     }
629     else
630     {
631         int i_move;
632
633         i_move = p_httpt->i_host_count - i - 1;
634
635         if( i_move > 0 )
636         {
637             memmove( &p_httpt->host[i],
638                      &p_httpt->host[i+1],
639                      i_move * sizeof( httpd_host_t * ) );
640         }
641
642         p_httpt->i_host_count--;
643         p_httpt->host = realloc( p_httpt->host,
644                                  p_httpt->i_host_count * sizeof( httpd_host_t * ) );
645     }
646
647     vlc_mutex_unlock( &p_httpt->host_lock );
648 }
649 static void             UnregisterHost( httpd_t *p_httpd, httpd_host_t *p_host )
650 {
651     _UnregisterHost( p_httpd->p_sys, p_host );
652 }
653
654
655 static void __RegisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
656 {
657     /* add a new file */
658     if( p_httpt->i_file_count )
659     {
660         p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *)  * ( p_httpt->i_file_count + 1 ) );
661     }
662     else
663     {
664         p_httpt->file = malloc( sizeof( httpd_file_t *) );
665     }
666
667     p_httpt->file[p_httpt->i_file_count++] = p_file;
668 }
669
670 static httpd_file_t    *_RegisterFile( httpd_sys_t *p_httpt,
671                                        char *psz_file, char *psz_mime,
672                                        char *psz_user, char *psz_password,
673                                        httpd_file_callback pf_get,
674                                        httpd_file_callback pf_post,
675                                        httpd_file_callback_args_t *p_args )
676 {
677     httpd_file_t    *p_file;
678     int i;
679
680     vlc_mutex_lock( &p_httpt->file_lock );
681     for( i = 0; i < p_httpt->i_file_count; i++ )
682     {
683         if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
684         {
685             break;
686         }
687     }
688     if( i < p_httpt->i_file_count )
689     {
690         vlc_mutex_unlock( &p_httpt->file_lock );
691         msg_Err( p_httpt, "%s already registered", psz_file );
692         return NULL;
693     }
694
695     p_file              = malloc( sizeof( httpd_file_t ) );
696     p_file->i_ref       = 0;
697     p_file->psz_file    = strdup( psz_file );
698     p_file->psz_mime    = strdup( psz_mime );
699     if( psz_user && *psz_user )
700     {
701         p_file->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
702         p_file->psz_user              = strdup( psz_user );
703         p_file->psz_password          = strdup( psz_password );
704     }
705     else
706     {
707         p_file->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
708         p_file->psz_user              = NULL;
709         p_file->psz_password          = NULL;
710     }
711
712     p_file->b_stream          = VLC_FALSE;
713     p_file->p_sys             = p_args;
714     p_file->pf_get            = pf_get;
715     p_file->pf_post           = pf_post;
716
717     p_file->i_buffer_size     = 0;
718     p_file->i_buffer_last_pos = 0;
719     p_file->i_buffer_pos      = 0;
720     p_file->p_buffer          = NULL;
721
722     p_file->i_header_size     = 0;
723     p_file->p_header          = NULL;
724
725     __RegisterFile( p_httpt, p_file );
726
727     vlc_mutex_unlock( &p_httpt->file_lock );
728
729     return p_file;
730 }
731 static httpd_file_t     *RegisterFile( httpd_t *p_httpd,
732                                        char *psz_file, char *psz_mime,
733                                        char *psz_user, char *psz_password,
734                                        httpd_file_callback pf_get,
735                                        httpd_file_callback pf_post,
736                                        httpd_file_callback_args_t *p_args )
737 {
738     return( _RegisterFile( p_httpd->p_sys,
739                            psz_file, psz_mime, psz_user, psz_password,
740                            pf_get, pf_post, p_args ) );
741 }
742
743 static httpd_stream_t  *_RegisterStream( httpd_sys_t *p_httpt,
744                                          char *psz_file, char *psz_mime,
745                                          char *psz_user, char *psz_password )
746 {
747     httpd_stream_t    *p_stream;
748     int i;
749
750     vlc_mutex_lock( &p_httpt->file_lock );
751     for( i = 0; i < p_httpt->i_file_count; i++ )
752     {
753         if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
754         {
755             break;
756         }
757     }
758     if( i < p_httpt->i_file_count )
759     {
760         vlc_mutex_unlock( &p_httpt->file_lock );
761         msg_Err( p_httpt, "%s already registered", psz_file );
762         return NULL;
763     }
764
765     p_stream              = malloc( sizeof( httpd_stream_t ) );
766     p_stream->i_ref       = 0;
767     p_stream->psz_file    = strdup( psz_file );
768     p_stream->psz_mime    = strdup( psz_mime );
769     if( psz_user && *psz_user )
770     {
771         p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
772         p_stream->psz_user              = strdup( psz_user );
773         p_stream->psz_password          = strdup( psz_password );
774     }
775     else
776     {
777         p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
778         p_stream->psz_user              = NULL;
779         p_stream->psz_password          = NULL;
780     }
781
782     p_stream->b_stream        = VLC_TRUE;
783     p_stream->p_sys           = NULL;
784     p_stream->pf_get          = NULL;
785     p_stream->pf_post         = NULL;
786
787     p_stream->i_buffer_size   = 5*1024*1024;
788     p_stream->i_buffer_pos      = 0;
789     p_stream->i_buffer_last_pos = 0;
790     p_stream->p_buffer        = malloc( p_stream->i_buffer_size );
791
792     p_stream->i_header_size   = 0;
793     p_stream->p_header        = NULL;
794
795     __RegisterFile( p_httpt, p_stream );
796
797     vlc_mutex_unlock( &p_httpt->file_lock );
798
799     return p_stream;
800 }
801 static httpd_stream_t   *RegisterStream( httpd_t *p_httpd,
802                                          char *psz_file, char *psz_mime,
803                                          char *psz_user, char *psz_password )
804 {
805     return( _RegisterStream( p_httpd->p_sys,
806                              psz_file, psz_mime, psz_user, psz_password ) );
807 }
808
809 static void            _UnregisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
810 {
811     int i;
812
813     vlc_mutex_lock( &p_httpt->file_lock );
814     for( i = 0; i < p_httpt->i_file_count; i++ )
815     {
816         if( !strcmp( p_file->psz_file, p_httpt->file[i]->psz_file ) )
817         {
818             break;
819         }
820     }
821     if( i >= p_httpt->i_file_count )
822     {
823         vlc_mutex_unlock( &p_httpt->file_lock );
824         msg_Err( p_httpt, "cannot unregister file" );
825         return;
826     }
827
828     if( p_file->i_ref > 0 )
829     {
830         httpd_connection_t *p_con;
831         /* force closing all connection for this file */
832         msg_Err( p_httpt, "closing all client connection" );
833
834         vlc_mutex_lock( &p_httpt->connection_lock );
835         for( p_con = p_httpt->p_first_connection; p_con != NULL; )
836         {
837             httpd_connection_t *p_next;
838
839             p_next = p_con->p_next;
840             if( p_con->p_file == p_file )
841             {
842                 httpd_ConnnectionClose( p_httpt, p_con );
843             }
844             p_con = p_next;
845         }
846         vlc_mutex_unlock( &p_httpt->connection_lock );
847     }
848
849     FREE( p_file->psz_file );
850     FREE( p_file->psz_mime );
851     if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
852     {
853         FREE( p_file->psz_user );
854         FREE( p_file->psz_password );
855     }
856     FREE( p_file->p_buffer );
857     FREE( p_file->p_header );
858
859     FREE( p_file );
860
861
862     if( p_httpt->i_file_count == 1 )
863     {
864         FREE( p_httpt->file );
865         p_httpt->i_file_count = 0;
866     }
867     else
868     {
869         int i_move;
870
871         i_move = p_httpt->i_file_count - i - 1;
872         if( i_move > 0  )
873         {
874             memmove( &p_httpt->file[i], &p_httpt->file[i + 1], sizeof( httpd_file_t *) * i_move );
875         }
876         p_httpt->i_file_count--;
877         p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * p_httpt->i_file_count );
878     }
879
880     vlc_mutex_unlock( &p_httpt->file_lock );
881 }
882 static void            UnregisterFile( httpd_t *p_httpd, httpd_file_t *p_file )
883 {
884     _UnregisterFile( p_httpd->p_sys, p_file );
885 }
886
887 static void             UnregisterStream( httpd_t *p_httpd, httpd_stream_t *p_stream )
888 {
889     _UnregisterFile( p_httpd->p_sys, p_stream );
890 }
891
892
893
894 static int             _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
895 {
896     int i_count;
897     int i_pos;
898
899     if( i_data <= 0 || p_data == NULL )
900     {
901         return( VLC_SUCCESS );
902     }
903     //fprintf( stderr, "## i_data=%d pos=%lld\n", i_data, p_stream->i_buffer_pos );
904
905     vlc_mutex_lock( &p_httpt->file_lock );
906
907     /* save this pointer (to be used by new connection) */
908     p_stream->i_buffer_last_pos = p_stream->i_buffer_pos;
909
910     i_pos = p_stream->i_buffer_pos % p_stream->i_buffer_size;
911     i_count = i_data;
912     while( i_count > 0)
913     {
914         int i_copy;
915
916         i_copy = __MIN( i_count, p_stream->i_buffer_size - i_pos );
917
918         memcpy( &p_stream->p_buffer[i_pos],
919                 p_data,
920                 i_copy );
921
922         i_pos = ( i_pos + i_copy ) % p_stream->i_buffer_size;
923         i_count -= i_copy;
924         p_data += i_copy;
925     }
926
927     p_stream->i_buffer_pos += i_data;
928     vlc_mutex_unlock( &p_httpt->file_lock );
929
930     return( VLC_SUCCESS );
931 }
932 static int             SendStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
933 {
934     return( _SendStream( p_httpd->p_sys, p_stream, p_data, i_data ) );
935 }
936
937 static int             HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
938 {
939     httpd_sys_t *p_httpt = p_httpd->p_sys;
940
941     vlc_mutex_lock( &p_httpt->file_lock );
942
943     FREE( p_stream->p_header );
944     if( p_data == NULL || i_data <= 0 )
945     {
946         p_stream->i_header_size = 0;
947     }
948     else
949     {
950         p_stream->i_header_size = i_data;
951         p_stream->p_header = malloc( i_data );
952         memcpy( p_stream->p_header,
953                 p_data,
954                 i_data );
955     }
956     vlc_mutex_unlock( &p_httpt->file_lock );
957
958     return( VLC_SUCCESS );
959 }
960
961 static void httpd_info_add_ss( httpd_info_t *p_info, char *name, char *value )
962 {
963     if( p_info->i_count == 0 )
964     {
965         p_info->info = malloc( sizeof( httpd_val_t ) );
966     }
967     else
968     {
969         p_info->info =
970             realloc( p_info->info,
971                      sizeof( httpd_val_t ) * ( p_info->i_count + 1 ) );
972     }
973     p_info->info[p_info->i_count].psz_name  = strdup( name );
974     p_info->info[p_info->i_count].psz_value = strdup( value ? value : "(null)");
975     p_info->i_count++;
976 }
977
978 static void httpd_info_add_si( httpd_info_t *p_info, char *name, int i_value )
979 {
980     char v[40];
981
982     sprintf( v, "%d", i_value );
983     httpd_info_add_ss( p_info, name, v );
984 }
985
986 static void httpd_info_add_sp( httpd_info_t *p_info, char *name, void *value )
987 {
988     char v[40];
989
990     sprintf( v, "%p", value );
991     httpd_info_add_ss( p_info, name, v );
992 }
993
994
995 static int Control( httpd_t *p_httpd,
996                     int i_query, void *arg1, void *arg2 )
997 {
998     httpd_sys_t  *p_httpt = p_httpd->p_sys;
999     httpd_info_t *p_info;
1000     httpd_connection_t *p_con;
1001     int i;
1002     void *id;
1003
1004     switch( i_query )
1005     {
1006         case HTTPD_GET_HOSTS:
1007             p_info = arg1;
1008             p_info->i_count = 0;
1009             vlc_mutex_lock( &p_httpt->host_lock );
1010             for( i = 0; i < p_httpt->i_host_count; i++ )
1011             {
1012                 httpd_info_add_sp( p_info,
1013                                    "id", p_httpt->host[i] );
1014                 httpd_info_add_ss( p_info,
1015                                    "host", p_httpt->host[i]->psz_host_addr );
1016                 httpd_info_add_ss( p_info,
1017                                    "ip",
1018                                    inet_ntoa(p_httpt->host[i]->sock.sin_addr));
1019                 httpd_info_add_si( p_info,
1020                                    "port", p_httpt->host[i]->i_port );
1021             }
1022             vlc_mutex_unlock( &p_httpt->host_lock );
1023             return VLC_SUCCESS;
1024         case HTTPD_GET_URLS:
1025             p_info = arg1;
1026             p_info->i_count = 0;
1027             /* we can't take file_lock */
1028             for( i = 0; i < p_httpt->i_file_count; i++ )
1029             {
1030                 httpd_info_add_sp( p_info,
1031                                    "id", p_httpt->file[i] );
1032                 httpd_info_add_si( p_info,
1033                                    "stream", p_httpt->file[i]->b_stream ? 1 : 0 );
1034                 httpd_info_add_ss( p_info,
1035                                    "url", p_httpt->file[i]->psz_file );
1036                 httpd_info_add_ss( p_info,
1037                                    "mime", p_httpt->file[i]->psz_mime );
1038                 httpd_info_add_si( p_info,
1039                                    "protected", p_httpt->file[i]->psz_user ? 1 : 0 );
1040                 httpd_info_add_si( p_info,
1041                                    "used", p_httpt->file[i]->i_ref );
1042             }
1043             return VLC_SUCCESS;
1044         case HTTPD_GET_CONNECTIONS:
1045             p_info = arg1;
1046             p_info->i_count = 0;
1047             /* we can't take lock */
1048             for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
1049             {
1050                 if( p_con->i_state != HTTPD_CONNECTION_TO_BE_CLOSED )
1051                 {
1052                     httpd_info_add_sp( p_info,
1053                                        "id", p_con );
1054                     httpd_info_add_ss( p_info,
1055                                        "ip", inet_ntoa( p_con->sock.sin_addr ) );
1056                     httpd_info_add_ss( p_info,
1057                                        "url", p_con->psz_file );
1058                     httpd_info_add_si( p_info,
1059                                        "status", p_con->i_http_error );
1060                 }
1061             }
1062             return VLC_SUCCESS;
1063         case HTTPD_GET_ACL:
1064             p_info = arg1;
1065             p_info->i_count = 0;
1066             return VLC_EGENERIC;
1067
1068         case HTTPD_SET_CLOSE:
1069             sscanf( arg1, "%p", &id );
1070             fprintf( stderr, "Control: HTTPD_SET_CLOSE: id=%p", id );
1071
1072             for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
1073             {
1074                 if( (void*)p_con == id )
1075                 {
1076                     /* XXX don't free p_con as it could be the one that it is sending ... */
1077                     p_con->i_state = HTTPD_CONNECTION_TO_BE_CLOSED;
1078                     return VLC_SUCCESS;
1079                 }
1080             }
1081             return VLC_EGENERIC;
1082
1083         case HTTPD_SET_ACL:
1084             sscanf( arg1, "%p", &id );
1085             fprintf( stderr, "Control: %p", id );
1086         default:
1087             return VLC_EGENERIC;
1088     }
1089 }
1090
1091 /****************************************************************************/
1092 /****************************************************************************/
1093 /****************************************************************************/
1094 /****************************************************************************/
1095 /****************************************************************************/
1096
1097 static int  httpd_page_400_get( httpd_file_callback_args_t *p_args,
1098                                 uint8_t *p_request, int i_request,
1099                                 uint8_t **pp_data, int *pi_data )
1100 {
1101     char *p;
1102
1103     p = *pp_data = malloc( 1024 );
1104
1105     p += sprintf( p, "<html>\n" );
1106     p += sprintf( p, "<head>\n" );
1107     p += sprintf( p, "<title>Error 400</title>\n" );
1108     p += sprintf( p, "</head>\n" );
1109     p += sprintf( p, "<body>\n" );
1110     p += sprintf( p, "<h1><center> 400  Bad Request</center></h1>\n" );
1111     p += sprintf( p, "<hr />\n" );
1112     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
1113     p += sprintf( p, "</body>\n" );
1114     p += sprintf( p, "</html>\n" );
1115
1116     *pi_data = strlen( *pp_data ) + 1;
1117
1118     return VLC_SUCCESS;
1119 }
1120
1121 static int  httpd_page_401_get( httpd_file_callback_args_t *p_args,
1122                                 uint8_t *p_request, int i_request,
1123                                 uint8_t **pp_data, int *pi_data )
1124 {
1125     char *p;
1126
1127     p = *pp_data = malloc( 1024 );
1128
1129     p += sprintf( p, "<html>\n" );
1130     p += sprintf( p, "<head>\n" );
1131     p += sprintf( p, "<title>Error 401</title>\n" );
1132     p += sprintf( p, "</head>\n" );
1133     p += sprintf( p, "<body>\n" );
1134     p += sprintf( p, "<h1><center> 401 authentification needed</center></h1>\n" );
1135     p += sprintf( p, "<hr />\n" );
1136     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
1137     p += sprintf( p, "</body>\n" );
1138     p += sprintf( p, "</html>\n" );
1139
1140     *pi_data = strlen( *pp_data ) + 1;
1141
1142     return VLC_SUCCESS;
1143 }
1144 static int  httpd_page_404_get( httpd_file_callback_args_t *p_args,
1145                                 uint8_t *p_request, int i_request,
1146                                 uint8_t **pp_data, int *pi_data )
1147 {
1148     char *p;
1149
1150     p = *pp_data = malloc( 1024 );
1151
1152     p += sprintf( p, "<html>\n" );
1153     p += sprintf( p, "<head>\n" );
1154     p += sprintf( p, "<title>Error 404</title>\n" );
1155     p += sprintf( p, "</head>\n" );
1156     p += sprintf( p, "<body>\n" );
1157     p += sprintf( p, "<h1><center> 404 Ressource not found</center></h1>\n" );
1158     p += sprintf( p, "<hr />\n" );
1159     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
1160     p += sprintf( p, "</body>\n" );
1161     p += sprintf( p, "</html>\n" );
1162
1163     *pi_data = strlen( *pp_data ) + 1;
1164
1165     return VLC_SUCCESS;
1166 }
1167
1168 #if 0
1169 static int httpd_BanIP( httpd_sys_t *p_httpt, char * psz_new_banned_ip)
1170 {
1171     httpd_banned_ip_t *p_new_banned_ip ;
1172
1173     p_new_banned_ip = malloc( sizeof( httpd_banned_ip_t ) );
1174     if( !p_new_banned_ip )
1175     {
1176         return -1;
1177     }
1178     p_new_banned_ip->p_next=NULL;
1179     p_new_banned_ip->psz_ip = malloc( strlen( psz_new_banned_ip ) + 1 );
1180     if( !p_new_banned_ip->psz_ip )
1181     {
1182         return -2;
1183     }
1184
1185     strcpy( p_new_banned_ip->psz_ip, psz_new_banned_ip );
1186
1187     msg_Dbg( p_httpt, "Banning IP %s", psz_new_banned_ip );
1188
1189     if( p_httpt->p_first_banned_ip )
1190     {
1191         httpd_banned_ip_t *p_last;
1192
1193         p_last = p_httpt->p_first_banned_ip;
1194         while( p_last->p_next )
1195         {
1196             p_last = p_last->p_next;
1197         }
1198
1199         p_last->p_next = p_new_banned_ip;
1200         p_new_banned_ip->p_prev = p_last;
1201     }
1202     else
1203     {
1204         p_new_banned_ip->p_prev = NULL;
1205
1206         p_httpt->p_first_banned_ip = p_new_banned_ip;
1207     }
1208
1209     p_httpt->i_banned_ip_count++;
1210     return 0;
1211 }
1212 #endif
1213 static httpd_banned_ip_t *httpd_GetbannedIP( httpd_sys_t *p_httpt, char *psz_ip )
1214 {
1215     httpd_banned_ip_t *p_ip;
1216
1217     p_ip = p_httpt->p_first_banned_ip;
1218
1219     while( p_ip)
1220     {
1221         if( strcmp( psz_ip, p_ip->psz_ip ) == 0 )
1222         {
1223             return p_ip;
1224         }
1225         p_ip = p_ip->p_next;
1226     }
1227
1228     return NULL;
1229 }
1230
1231 static int httpd_UnbanIP( httpd_sys_t *p_httpt, httpd_banned_ip_t *p_banned_ip )
1232 {
1233     if(!p_banned_ip)
1234     {
1235         return -1;
1236     }
1237
1238     msg_Dbg( p_httpt, "Unbanning IP %s",p_banned_ip->psz_ip);
1239
1240     /* first cut out from list */
1241     if( p_banned_ip->p_prev )
1242     {
1243         p_banned_ip->p_prev->p_next = p_banned_ip->p_next;
1244     }
1245     else
1246     {
1247         p_httpt->p_first_banned_ip = p_banned_ip->p_next;
1248     }
1249
1250     if( p_banned_ip->p_next )
1251     {
1252         p_banned_ip->p_next->p_prev = p_banned_ip->p_prev;
1253     }
1254
1255     FREE( p_banned_ip->psz_ip );
1256     FREE( p_banned_ip );
1257
1258     p_httpt->i_banned_ip_count--;
1259
1260     return 0;
1261 }
1262
1263 static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_in *p_sock )
1264 {
1265     httpd_connection_t *p_con;
1266
1267     msg_Dbg( p_httpt, "new connection from %s", inet_ntoa( p_sock->sin_addr ) );
1268
1269     /* verify if it's a banned ip */
1270     if(httpd_GetbannedIP( p_httpt,inet_ntoa( p_sock->sin_addr ) ) )
1271     {
1272         msg_Dbg( p_httpt, "Ip %s banned : closing connection", inet_ntoa( p_sock->sin_addr ) );
1273         close(fd);
1274         return;
1275     }
1276
1277     /* create a new connection and link it */
1278     p_con = malloc( sizeof( httpd_connection_t ) );
1279     p_con->i_state  = HTTPD_CONNECTION_RECEIVING_REQUEST;
1280     p_con->fd       = fd;
1281     p_con->i_last_activity_date = mdate();
1282
1283     p_con->sock     = *p_sock;
1284     p_con->psz_file = NULL;
1285     p_con->i_http_error = 0;
1286     p_con->psz_user = NULL;
1287     p_con->psz_password = NULL;
1288     p_con->p_file   = NULL;
1289
1290     p_con->i_request_size = 0;
1291     p_con->p_request = NULL;
1292
1293     p_con->i_buffer = 0;
1294     p_con->i_buffer_size = 8096;
1295     p_con->p_buffer = malloc( p_con->i_buffer_size );
1296
1297     p_con->i_stream_pos = 0; // updated by httpd_thread */
1298     p_con->p_next = NULL;
1299
1300     if( p_httpt->p_first_connection )
1301     {
1302         httpd_connection_t *p_last;
1303
1304         p_last = p_httpt->p_first_connection;
1305         while( p_last->p_next )
1306         {
1307             p_last = p_last->p_next;
1308         }
1309
1310         p_last->p_next = p_con;
1311         p_con->p_prev = p_last;
1312     }
1313     else
1314     {
1315         p_con->p_prev = NULL;
1316
1317         p_httpt->p_first_connection = p_con;
1318     }
1319
1320     p_httpt->i_connection_count++;
1321 }
1322
1323 static void httpd_ConnnectionClose( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1324 {
1325     msg_Dbg( p_httpt, "close connection from %s", inet_ntoa( p_con->sock.sin_addr ) );
1326
1327     p_httpt->i_connection_count--;
1328     /* first cut out from list */
1329     if( p_con->p_prev )
1330     {
1331         p_con->p_prev->p_next = p_con->p_next;
1332     }
1333     else
1334     {
1335         p_httpt->p_first_connection = p_con->p_next;
1336     }
1337
1338     if( p_con->p_next )
1339     {
1340         p_con->p_next->p_prev = p_con->p_prev;
1341     }
1342
1343     if( p_con->p_file ) p_con->p_file->i_ref--;
1344     FREE( p_con->psz_file );
1345
1346     FREE( p_con->p_buffer );
1347     SOCKET_CLOSE( p_con->fd );
1348
1349     FREE( p_con->psz_user );
1350     FREE( p_con->psz_password );
1351
1352     FREE( p_con->p_request );
1353     free( p_con );
1354 }
1355
1356 static void httpd_RequestGetWord( char *word, int i_word_max, char **pp_buffer, char *p_end )
1357 {
1358     char *p = *pp_buffer;
1359     int i;
1360
1361     while( p < p_end && *p && ( *p == ' ' || *p == '\t' ) )
1362     {
1363         p++;
1364     }
1365
1366     i = 0;
1367     for( i = 0; i < i_word_max && p < p_end && *p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r'; i++,p++)
1368     {
1369         word[i] = *p;
1370     }
1371
1372     word[__MIN( i, i_word_max -1 )] = '\0';
1373
1374     *pp_buffer = p;
1375
1376 }
1377 static int httpd_RequestNextLine( char **pp_buffer, char *p_end )
1378 {
1379     char *p;
1380
1381     for( p = *pp_buffer; p < p_end; p++ )
1382     {
1383         if( p + 1 < p_end && *p == '\n' )
1384         {
1385             *pp_buffer = p + 1;
1386             return VLC_SUCCESS;
1387         }
1388         if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
1389         {
1390             *pp_buffer = p + 2;
1391             return VLC_SUCCESS;
1392         }
1393     }
1394     *pp_buffer = p_end;
1395     return VLC_EGENERIC;
1396 }
1397
1398 //char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1399 static void b64_decode( char *dest, char *src )
1400 {
1401     int  i_level;
1402     int  last = 0;
1403     int  b64[256] = {
1404         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
1405         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
1406         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
1407         52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
1408         -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
1409         15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
1410         -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
1411         41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
1412         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
1413         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
1414         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
1415         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
1416         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
1417         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
1418         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
1419         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
1420         };
1421
1422     for( i_level = 0; *src != '\0'; src++ )
1423     {
1424         int  c;
1425
1426         c = b64[(unsigned int)*src];
1427         if( c == -1 )
1428         {
1429             src++;
1430             continue;
1431         }
1432
1433         switch( i_level )
1434         {
1435             case 0:
1436                 i_level++;
1437                 break;
1438             case 1:
1439                 *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
1440                 i_level++;
1441                 break;
1442             case 2:
1443                 *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
1444                 i_level++;
1445                 break;
1446             case 3:
1447                 *dest++ = ( ( last &0x03 ) << 6 ) | c;
1448                 i_level = 0;
1449         }
1450         last = c;
1451     }
1452
1453     *dest = '\0';
1454 }
1455
1456 static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1457 {
1458     char *psz_status;
1459     char *p, *p_end;
1460
1461     int  i;
1462     int  b_xplaystream = VLC_FALSE;
1463     char command[32];
1464     char url[1024];
1465     char version[32];
1466     char user[512] = "";
1467     char password[512] = "";
1468
1469     msg_Dbg( p_httpt, "new request=\n%s", p_con->p_buffer );
1470
1471
1472     p = p_con->p_buffer;
1473     p_end = p + strlen( p ) + 1;
1474
1475     httpd_RequestGetWord( command, 32, &p, p_end );
1476     httpd_RequestGetWord( url, 1024, &p, p_end );
1477     httpd_RequestGetWord( version, 32, &p, p_end );
1478     //msg_Dbg( p_httpt, "ask =%s= =%s= =%s=", command, url, version );
1479
1480     p_con->p_request      = NULL;
1481     p_con->i_request_size = 0;
1482     if( !strcmp( command, "GET" ) )
1483     {
1484         p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
1485     }
1486     else if( !strcmp( command, "POST" ))
1487     {
1488         p_con->i_method = HTTPD_CONNECTION_METHOD_POST;
1489     }
1490     else if( !strcmp( command, "HEAD" ))
1491     {
1492         p_con->i_method = HTTPD_CONNECTION_METHOD_HEAD;
1493     }
1494     else
1495     {
1496         /* unimplemented */
1497         p_con->psz_file = strdup( "/501.html" );
1498         p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
1499         p_con->i_http_error = 501;
1500         goto create_header;
1501     }
1502
1503     if( strcmp( version, "HTTP/1.0" ) && strcmp( version, "HTTP/1.1" ) )
1504     {
1505         p_con->psz_file = strdup( "/505.html" );
1506         p_con->i_http_error = 505;
1507
1508         goto create_header;
1509     }
1510
1511     /* parse headers */
1512     for( ;; )
1513     {
1514         char header[1024];
1515
1516         if( httpd_RequestNextLine( &p, p_end ) )
1517         {
1518             //msg_Dbg( p_httpt, "failled new line" );
1519             break;;
1520         }
1521         //msg_Dbg( p_httpt, "new line=%s", p );
1522
1523         httpd_RequestGetWord( header, 1024, &p, p_end );
1524         if( !strcmp( header, "\r\n" ) || !strcmp( header, "\n" ) )
1525         {
1526             break;
1527         }
1528
1529         if( !strcmp( header, "Authorization:" ) )
1530         {
1531             char method[32];
1532
1533             httpd_RequestGetWord( method, 32, &p, p_end );
1534             if( !strcasecmp( method, "BASIC" ) )
1535             {
1536                 char basic[1024];
1537                 char decoded[1024];
1538
1539                 httpd_RequestGetWord( basic, 1024, &p, p_end );
1540 //                msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
1541                 b64_decode( decoded, basic );
1542 //                msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
1543                 if( strchr( decoded, ':' ) )
1544                 {
1545                     char *p = strchr( decoded, ':' );
1546
1547                     p[0] = '\0'; p++;
1548                     strcpy( user, decoded );
1549                     strcpy( password, p );
1550                 }
1551             }
1552         }
1553         else if( !strcmp( header, "Pragma:" ) )
1554         {
1555             char method[128];
1556
1557             httpd_RequestGetWord( method, 128, &p, p_end );
1558             if( !strcasecmp( method, "xPlayStrm=1" ) )
1559             {
1560                 b_xplaystream = VLC_TRUE;
1561             }
1562         }
1563     }
1564
1565     if( strchr( url, '?' ) )
1566     {
1567         char *p_request = strchr( url, '?' );
1568         *p_request++ = '\0';
1569         p_con->psz_file = strdup( url );
1570         p_con->p_request = strdup( p_request );
1571         p_con->i_request_size = strlen( p_con->p_request );
1572     }
1573     else
1574     {
1575         p_con->psz_file = strdup( url );
1576     }
1577
1578     /* fix p_request */
1579     if( p_con->i_method == HTTPD_CONNECTION_METHOD_POST )
1580     {
1581         char *p_request;
1582         if( strstr( p_con->p_buffer, "\r\n\r\n" ) )
1583         {
1584             p_request = strstr( p_con->p_buffer, "\r\n\r\n" ) + 4;
1585         }
1586         else if( strstr( p_con->p_buffer, "\n\n" ) )
1587         {
1588             p_request = strstr( p_con->p_buffer, "\n\n" ) + 2;
1589         }
1590         else
1591         {
1592             p_request = NULL;
1593         }
1594         if( p_request && p_request < p_end )
1595         {
1596             p_con->i_request_size = p_end - p_request;
1597             p_con->p_request = malloc( p_con->i_request_size + 1);
1598
1599             memcpy( p_con->p_request,
1600                     p_request,
1601                     p_con->i_request_size );
1602
1603             p_con->p_request[p_con->i_request_size] = '\0';
1604         }
1605     }
1606     p_con->i_http_error = 200;
1607
1608 create_header:
1609     //msg_Dbg( p_httpt, "ask %s %s %d", command, p_con->psz_file, p_con->i_http_error );
1610     FREE( p_con->p_buffer );
1611     p_con->i_buffer = 0;
1612     p_con->i_buffer_size = 0;
1613
1614     //vlc_mutex_lock( &p_httpt->file_lock );
1615 search_file:
1616     /* search file */
1617     p_con->p_file = NULL;
1618     for( i = 0; i < p_httpt->i_file_count; i++ )
1619     {
1620         if( !strcmp( p_httpt->file[i]->psz_file, p_con->psz_file ) )
1621         {
1622             if( p_httpt->file[i]->b_stream ||
1623                 p_con->i_method == HTTPD_CONNECTION_METHOD_HEAD ||
1624                 ( p_con->i_method == HTTPD_CONNECTION_METHOD_GET  && p_httpt->file[i]->pf_get ) ||
1625                 ( p_con->i_method == HTTPD_CONNECTION_METHOD_POST && p_httpt->file[i]->pf_post ) )
1626             {
1627                 p_con->p_file = p_httpt->file[i];
1628                 break;
1629             }
1630         }
1631     }
1632
1633     if( !p_con->p_file )
1634     {
1635         p_con->psz_file = strdup( "/404.html" );
1636         p_con->i_http_error = 404;
1637         p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
1638
1639         /* XXX be sure that "/404.html" exist else ... */
1640         goto search_file;
1641     }
1642     if( p_con->p_file->i_authenticate_method == HTTPD_AUTHENTICATE_BASIC )
1643     {
1644         if( strcmp( user, p_con->p_file->psz_user ) ||
1645             strcmp( password, p_con->p_file->psz_password ) )
1646         {
1647             p_con->psz_file = strdup( "/401.html" );
1648             strcpy( user, p_con->p_file->psz_user );
1649             p_con->i_http_error = 401;
1650             p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
1651
1652             /* XXX do not put password on 404 else ... */
1653             goto search_file;
1654         }
1655     }
1656     if( !strcmp( p_con->p_file->psz_mime, "video/x-ms-asf-stream" ) &&
1657         p_con->i_method == HTTPD_CONNECTION_METHOD_POST )
1658     {
1659         p_con->psz_file = strdup( "/400.html" );
1660         p_con->i_http_error = 400;
1661         p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
1662
1663         goto search_file;
1664     }
1665
1666     p_con->p_file->i_ref++;
1667 //    vlc_mutex_unlock( &p_httpt->file_lock );
1668
1669     switch( p_con->i_http_error )
1670     {
1671         case 200:
1672             psz_status = "OK";
1673             break;
1674         case 400:
1675             psz_status = "Bad Request";
1676             break;
1677         case 401:
1678             psz_status = "Authorization Required";
1679             break;
1680         default:
1681             psz_status = "Unknown";
1682             break;
1683     }
1684
1685     p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
1686
1687     p_con->i_buffer_size = 4096;
1688     p_con->i_buffer = 0;
1689
1690     /* we send stream header with this one */
1691     if( p_con->i_http_error == 200 && p_con->p_file->b_stream )
1692     {
1693         p_con->i_buffer_size += p_con->p_file->i_header_size;
1694     }
1695
1696     p = p_con->p_buffer = malloc( p_con->i_buffer_size );
1697
1698     p += sprintf( p, "HTTP/1.0 %d %s\r\n", p_con->i_http_error, psz_status );
1699
1700     /* Special mmsh case cludgy but ...*/
1701     if( !strcmp( p_con->p_file->psz_mime, "video/x-ms-asf-stream" ) &&
1702         p_con->i_method == HTTPD_CONNECTION_METHOD_GET )
1703     {
1704         p += sprintf( p, "Content-type: application/octet-stream\r\n" );
1705         p += sprintf( p, "Server: Cougar 4.1.0.3921\r\n" );
1706         p += sprintf( p, "Cache-Control: no-cache\r\n" );
1707         p += sprintf( p, "Pragma: no-cache\r\n" );
1708         p += sprintf( p, "Pragma: client-id=%d\r\n", rand()&0x7fff );
1709         p += sprintf( p, "Pragma: features=\"broadcast\"\r\n" );
1710
1711         if( !b_xplaystream )
1712         {
1713             p_con->i_method = HTTPD_CONNECTION_METHOD_ASFHEAD;
1714         }
1715     }
1716     else
1717     {
1718         p += sprintf( p, "Content-type: %s\r\n", p_con->p_file->psz_mime );
1719         p += sprintf( p, "Cache-Control: no-cache\r\n" );
1720     }
1721     if( p_con->i_http_error == 401 )
1722     {
1723         p += sprintf( p, "WWW-Authenticate: Basic realm=\"%s\"\r\n", user );
1724     }
1725 #if 0
1726     if( p_con->i_method == HTTPD_CONNECTION_METHOD_HEAD )
1727     {
1728         p += sprintf( p, "Content-Length: 0\r\n" );
1729     }
1730     else if( p_con->i_method == HTTPD_CONNECTION_METHOD_ASFHEAD &&
1731              p_con->p_file->i_header_size > 0 )
1732     {
1733         p += sprintf( p, "Content-Length: %d\r\n", p_con->p_file->i_header_size );
1734     }
1735 #endif
1736     p += sprintf( p, "\r\n" );
1737
1738     p_con->i_buffer_size = strlen( p_con->p_buffer );// + 1;
1739
1740     if( p_con->i_http_error == 200 &&
1741         p_con->i_method != HTTPD_CONNECTION_METHOD_HEAD &&
1742         p_con->p_file->b_stream && p_con->p_file->i_header_size > 0 )
1743     {
1744         /* add stream header */
1745         memcpy( &p_con->p_buffer[p_con->i_buffer_size],
1746                 p_con->p_file->p_header,
1747                 p_con->p_file->i_header_size );
1748         p_con->i_buffer_size += p_con->p_file->i_header_size;
1749     }
1750
1751     if( p_con->i_method == HTTPD_CONNECTION_METHOD_ASFHEAD )
1752     {
1753         p_con->i_method = HTTPD_CONNECTION_METHOD_HEAD;
1754     }
1755     //msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
1756 }
1757 #define HTTPD_STREAM_PACKET 10000
1758 static void httpd_Thread( httpd_sys_t *p_httpt )
1759 {
1760     httpd_file_t    *p_page_400;
1761     httpd_file_t    *p_page_401;
1762     httpd_file_t    *p_page_404;
1763
1764     httpd_connection_t *p_con;
1765
1766     msg_Info( p_httpt, "httpd started" );
1767
1768     p_page_400 = _RegisterFile( p_httpt,
1769                                 "/400.html", "text/html",
1770                                 NULL, NULL,
1771                                 httpd_page_400_get,
1772                                 NULL,
1773                                 (httpd_file_callback_args_t*)NULL );
1774
1775     p_page_401 = _RegisterFile( p_httpt,
1776                                 "/401.html", "text/html",
1777                                 NULL, NULL,
1778                                 httpd_page_401_get,
1779                                 NULL,
1780                                 (httpd_file_callback_args_t*)NULL );
1781     p_page_404 = _RegisterFile( p_httpt,
1782                                 "/404.html", "text/html",
1783                                 NULL, NULL,
1784                                 httpd_page_404_get,
1785                                 NULL,
1786                                 (httpd_file_callback_args_t*)NULL );
1787
1788     while( !p_httpt->b_die )
1789     {
1790         struct timeval  timeout;
1791         fd_set          fds_read;
1792         fd_set          fds_write;
1793         int             i_handle_max = 0;
1794         int             i_ret;
1795         int i;
1796         if( p_httpt->i_host_count <= 0 )
1797         {
1798             msleep( 100 * 1000 );
1799             continue;
1800         }
1801
1802         /* we will create a socket set with host and connection */
1803         FD_ZERO( &fds_read );
1804         FD_ZERO( &fds_write );
1805
1806         vlc_mutex_lock( &p_httpt->host_lock );
1807         vlc_mutex_lock( &p_httpt->connection_lock );
1808         for( i = 0; i < p_httpt->i_host_count; i++ )
1809         {
1810             FD_SET( p_httpt->host[i]->fd, &fds_read );
1811             i_handle_max = __MAX( i_handle_max, p_httpt->host[i]->fd );
1812         }
1813         for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1814         {
1815             /* no more than 10s of inactivity */
1816             if( p_con->i_last_activity_date + (mtime_t)HTTPD_CONNECTION_MAX_UNUSED < mdate() ||
1817                 p_con->i_state == HTTPD_CONNECTION_TO_BE_CLOSED)
1818             {
1819                 httpd_connection_t *p_next = p_con->p_next;
1820
1821                 msg_Dbg( p_httpt,  "close unused connection" );
1822                 httpd_ConnnectionClose( p_httpt, p_con );
1823                 p_con = p_next;
1824                 continue;
1825             }
1826
1827             if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM && p_con->i_stream_pos + HTTPD_STREAM_PACKET >= p_con->p_file->i_buffer_pos )
1828             {
1829                 p_con = p_con->p_next;
1830                 continue;
1831             }
1832
1833             if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1834             {
1835                 FD_SET( p_con->fd, &fds_read );
1836             }
1837             else
1838             {
1839                 FD_SET( p_con->fd, &fds_write );
1840             }
1841             i_handle_max = __MAX( i_handle_max, p_con->fd );
1842
1843             p_con = p_con->p_next;
1844         }
1845         vlc_mutex_unlock( &p_httpt->host_lock );
1846         vlc_mutex_unlock( &p_httpt->connection_lock );
1847
1848         /* we will wait 0.5s */
1849         timeout.tv_sec = 0;
1850         timeout.tv_usec = 500*1000;
1851
1852         i_ret = select( i_handle_max + 1,
1853                         &fds_read,
1854                         &fds_write,
1855                         NULL,
1856                         &timeout );
1857         if( i_ret == -1 && errno != EINTR )
1858         {
1859             msg_Warn( p_httpt, "cannot select sockets" );
1860             msleep( 1000 );
1861             continue;
1862         }
1863
1864         if( i_ret <= 0 )
1865         {
1866             continue;
1867         }
1868
1869         vlc_mutex_lock( &p_httpt->host_lock );
1870         /* accept/refuse new connection */
1871         for( i = 0; i < p_httpt->i_host_count; i++ )
1872         {
1873             int     i_sock_size = sizeof( struct sockaddr_in );
1874             struct  sockaddr_in sock;
1875             int     fd;
1876
1877             fd = accept( p_httpt->host[i]->fd, (struct sockaddr *)&sock,
1878                          &i_sock_size );
1879             if( fd > 0 )
1880             {
1881 #if defined( WIN32 ) || defined( UNDER_CE )
1882                 {
1883                     unsigned long i_dummy = 1;
1884                     ioctlsocket( fd, FIONBIO, &i_dummy );
1885                 }
1886 #else
1887                 fcntl( fd, F_SETFL, O_NONBLOCK );
1888 #endif
1889
1890                 if( p_httpt->i_connection_count >= HTTPD_MAX_CONNECTION )
1891                 {
1892                     msg_Warn( p_httpt, "max connection reached" );
1893                     SOCKET_CLOSE( fd );
1894                     continue;
1895                 }
1896                 /* create a new connection and link it */
1897                 httpd_ConnnectionNew( p_httpt, fd, &sock );
1898
1899             }
1900         }
1901         vlc_mutex_unlock( &p_httpt->host_lock );
1902
1903         vlc_mutex_lock( &p_httpt->file_lock );
1904         /* now do work for all connections */
1905         for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1906         {
1907             if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1908             {
1909                 int i_len;
1910                 /* read data */
1911                 i_len = recv( p_con->fd,
1912                               p_con->p_buffer + p_con->i_buffer,
1913                               p_con->i_buffer_size - p_con->i_buffer, 0 );
1914
1915
1916 #if defined( WIN32 ) || defined( UNDER_CE )
1917                 if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
1918 #else
1919                 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
1920 #endif
1921                 {
1922                     httpd_connection_t *p_next = p_con->p_next;
1923
1924                     httpd_ConnnectionClose( p_httpt, p_con );
1925                     p_con = p_next;
1926                 }
1927                 else if( i_len > 0 )
1928                 {
1929                     uint8_t *ptr;
1930                     p_con->i_last_activity_date = mdate();
1931                     p_con->i_buffer += i_len;
1932
1933                     ptr = p_con->p_buffer + p_con->i_buffer;
1934
1935                     if( ( p_con->i_buffer >= 2 && !strncmp( ptr - 2, "\n\n", 2 ) )||
1936                         ( p_con->i_buffer >= 4 && !strncmp( ptr - 4, "\r\n\r\n", 4 ) ) ||
1937                         p_con->i_buffer >= p_con->i_buffer_size )
1938                     {
1939                         p_con->p_buffer[__MIN( p_con->i_buffer, p_con->i_buffer_size - 1 )] = '\0';
1940                         httpd_ConnectionParseRequest( p_httpt, p_con );
1941                     }
1942
1943                     p_con = p_con->p_next;
1944                 }
1945                 else
1946                 {
1947                     p_con = p_con->p_next;
1948                 }
1949                 continue;   /* just for clarity */
1950             }
1951             else if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER || p_con->i_state == HTTPD_CONNECTION_SENDING_FILE )
1952             {
1953                 int i_len;
1954
1955                 /* write data */
1956                 if( p_con->i_buffer_size - p_con->i_buffer > 0 )
1957                 {
1958                     i_len = send( p_con->fd, p_con->p_buffer + p_con->i_buffer, p_con->i_buffer_size - p_con->i_buffer, 0 );
1959                 }
1960                 else
1961                 {
1962                     i_len = 0;
1963                 }
1964 //                msg_Warn( p_httpt, "on %d send %d bytes %s", p_con->i_buffer_size, i_len, p_con->p_buffer + p_con->i_buffer );
1965
1966 #if defined( WIN32 ) || defined( UNDER_CE )
1967                 if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
1968 #else
1969                 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
1970 #endif
1971                 {
1972                     httpd_connection_t *p_next = p_con->p_next;
1973
1974                     httpd_ConnnectionClose( p_httpt, p_con );
1975                     p_con = p_next;
1976                 }
1977                 else if( i_len > 0 )
1978                 {
1979                     p_con->i_last_activity_date = mdate();
1980                     p_con->i_buffer += i_len;
1981
1982                     if( p_con->i_buffer >= p_con->i_buffer_size )
1983                     {
1984                         if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER )
1985                         {
1986                             p_con->i_buffer_size = 0;
1987                             p_con->i_buffer = 0;
1988                             FREE( p_con->p_buffer );
1989
1990                             if( !p_con->p_file->b_stream || p_con->i_method == HTTPD_CONNECTION_METHOD_HEAD )
1991                             {
1992                                 p_con->i_state = HTTPD_CONNECTION_SENDING_FILE; // be sure to out from HTTPD_CONNECTION_SENDING_HEADER
1993                                 if( p_con->i_method == HTTPD_CONNECTION_METHOD_GET )
1994                                 {
1995                                     p_con->p_file->pf_get( p_con->p_file->p_sys,
1996                                                            p_con->p_request, p_con->i_request_size,
1997                                                            &p_con->p_buffer, &p_con->i_buffer_size );
1998                                 }
1999                                 else if( p_con->i_method == HTTPD_CONNECTION_METHOD_POST )
2000                                 {
2001                                     p_con->p_file->pf_post( p_con->p_file->p_sys,
2002                                                             p_con->p_request, p_con->i_request_size,
2003                                                             &p_con->p_buffer, &p_con->i_buffer_size );
2004                                 }
2005                                 else
2006                                 {
2007                                     /* HTTPD_CONNECTION_METHOD_HEAD for example */
2008                                     p_con->p_buffer = NULL;
2009                                     p_con->i_buffer_size = 0;
2010                                 }
2011                             }
2012                             else
2013                             {
2014                                 p_con->i_state = HTTPD_CONNECTION_SENDING_STREAM;
2015                                 p_con->i_stream_pos = p_con->p_file->i_buffer_last_pos;
2016                             }
2017                             p_con = p_con->p_next;
2018                         }
2019                         else
2020                         {
2021                             httpd_connection_t *p_next = p_con->p_next;
2022
2023                             httpd_ConnnectionClose( p_httpt, p_con );
2024                             p_con = p_next;
2025                         }
2026                     }
2027                     else
2028                     {
2029                         p_con = p_con->p_next;
2030                     }
2031                 }
2032                 else
2033                 {
2034                     p_con = p_con->p_next;
2035                 }
2036                 continue;   /* just for clarity */
2037             }
2038             else if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM )
2039             {
2040                 httpd_stream_t *p_stream = p_con->p_file;
2041                 int i_send;
2042                 int i_write;
2043
2044                 if( p_con->i_stream_pos < p_stream->i_buffer_pos )
2045                 {
2046                     int i_pos;
2047                     /* check if this p_con aren't to late */
2048                     if( p_con->i_stream_pos + p_stream->i_buffer_size < p_stream->i_buffer_pos )
2049                     {
2050                         fprintf( stderr, "fixing i_stream_pos (old=%lld i_buffer_pos=%lld\n",
2051                                  p_con->i_stream_pos, p_stream->i_buffer_pos  );
2052                         p_con->i_stream_pos = p_stream->i_buffer_last_pos;
2053                     }
2054
2055                     i_pos = p_con->i_stream_pos % p_stream->i_buffer_size;
2056                     /* size until end of buffer */
2057                     i_write = p_stream->i_buffer_size - i_pos;
2058                     /* is it more than valid data */
2059                     if( i_write >= p_stream->i_buffer_pos - p_con->i_stream_pos )
2060                     {
2061                         i_write = p_stream->i_buffer_pos - p_con->i_stream_pos;
2062                     }
2063                     /* limit to HTTPD_STREAM_PACKET */
2064                     if( i_write > HTTPD_STREAM_PACKET )
2065                     {
2066                         i_write = HTTPD_STREAM_PACKET;
2067                     }
2068                     i_send = send( p_con->fd, &p_stream->p_buffer[i_pos], i_write, 0 );
2069
2070 #if defined( WIN32 ) || defined( UNDER_CE )
2071                     if( ( i_send < 0 && WSAGetLastError() != WSAEWOULDBLOCK )|| ( i_send == 0 ) )
2072 #else
2073                     if( ( i_send < 0 && errno != EAGAIN && errno != EINTR )|| ( i_send == 0 ) )
2074 #endif
2075                     {
2076                         httpd_connection_t *p_next = p_con->p_next;
2077
2078                         httpd_ConnnectionClose( p_httpt, p_con );
2079                         p_con = p_next;
2080                         continue;
2081                     }
2082                     else if( i_send > 0 )
2083                     {
2084                         p_con->i_last_activity_date = mdate();
2085                         p_con->i_stream_pos += i_send;
2086                     }
2087                 }
2088                 p_con = p_con->p_next;
2089                 continue;   /* just for clarity */
2090             }
2091             else if( p_con->i_state != HTTPD_CONNECTION_TO_BE_CLOSED )
2092             {
2093                 msg_Warn( p_httpt, "cannot occur (Invalid p_con->i_state)" );
2094                 p_con = p_con->p_next;
2095             }
2096         }   /* for over connection */
2097
2098         vlc_mutex_unlock( &p_httpt->file_lock );
2099     }
2100
2101     msg_Info( p_httpt, "httpd stopped" );
2102
2103     _UnregisterFile( p_httpt, p_page_400 );
2104     _UnregisterFile( p_httpt, p_page_401 );
2105     _UnregisterFile( p_httpt, p_page_404 );
2106 }