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