2004-03-03 14:23:47 +01:00
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* httpd.c
|
|
|
|
|
*****************************************************************************
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
|
* Copyright (C) 2004-2006 VLC authors and VideoLAN
|
2007-04-05 18:42:16 +02:00
|
|
|
|
* Copyright © 2004-2007 Rémi Denis-Courmont
|
2004-03-06 02:14:28 +01:00
|
|
|
|
* $Id$
|
2004-03-03 14:23:47 +01:00
|
|
|
|
*
|
|
|
|
|
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
|
2005-05-22 13:36:59 +02:00
|
|
|
|
* Rémi Denis-Courmont <rem # videolan.org>
|
2004-03-03 14:23:47 +01:00
|
|
|
|
*
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
2004-03-03 14:23:47 +01:00
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU Lesser General Public License for more details.
|
2004-03-03 14:23:47 +01:00
|
|
|
|
*
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
2004-03-03 14:23:47 +01:00
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
2008-01-23 22:50:58 +01:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-05-31 20:56:22 +02:00
|
|
|
|
#include <vlc_common.h>
|
2008-02-25 16:45:21 +01:00
|
|
|
|
#include <vlc_httpd.h>
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2006-03-04 11:46:27 +01:00
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
2006-11-26 15:20:34 +01:00
|
|
|
|
#include <vlc_network.h>
|
|
|
|
|
#include <vlc_tls.h>
|
2007-03-06 18:27:18 +01:00
|
|
|
|
#include <vlc_strings.h>
|
2010-03-06 11:21:02 +01:00
|
|
|
|
#include <vlc_rand.h>
|
2011-01-12 19:37:51 +01:00
|
|
|
|
#include <vlc_charset.h>
|
2011-12-18 18:58:23 +01:00
|
|
|
|
#include <vlc_url.h>
|
2012-08-28 18:07:06 +02:00
|
|
|
|
#include <vlc_mime.h>
|
2013-08-16 16:42:40 +02:00
|
|
|
|
#include <vlc_block.h>
|
2006-12-01 21:26:05 +01:00
|
|
|
|
#include "../libvlc.h"
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2004-07-05 17:43:56 +02:00
|
|
|
|
#include <string.h>
|
2004-10-04 15:34:42 +02:00
|
|
|
|
#include <errno.h>
|
2013-12-29 15:15:46 +01:00
|
|
|
|
#include <unistd.h>
|
2004-10-01 17:56:10 +02:00
|
|
|
|
|
2007-02-21 18:58:12 +01:00
|
|
|
|
#ifdef HAVE_POLL
|
|
|
|
|
# include <poll.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-06-05 15:41:18 +02:00
|
|
|
|
#if defined( _WIN32 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
# include <winsock2.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <sys/socket.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-06-05 15:41:18 +02:00
|
|
|
|
#if defined( _WIN32 )
|
2005-10-22 18:23:01 +02:00
|
|
|
|
/* We need HUGE buffer otherwise TCP throughput is very limited */
|
|
|
|
|
#define HTTPD_CL_BUFSIZE 1000000
|
|
|
|
|
#else
|
|
|
|
|
#define HTTPD_CL_BUFSIZE 10000
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-03-09 21:46:43 +01:00
|
|
|
|
static void httpd_ClientClean( httpd_client_t *cl );
|
2013-08-16 16:42:40 +02:00
|
|
|
|
static void httpd_AppendData( httpd_stream_t *stream, uint8_t *p_data, int i_data );
|
2004-03-09 21:46:43 +01:00
|
|
|
|
|
2006-12-01 21:26:05 +01:00
|
|
|
|
/* each host run in his own thread */
|
|
|
|
|
struct httpd_host_t
|
|
|
|
|
{
|
|
|
|
|
VLC_COMMON_MEMBERS
|
|
|
|
|
|
|
|
|
|
/* ref count */
|
2009-01-14 21:07:31 +01:00
|
|
|
|
unsigned i_ref;
|
2006-12-01 21:26:05 +01:00
|
|
|
|
|
|
|
|
|
/* address/port and socket for listening at connections */
|
2007-02-21 18:58:12 +01:00
|
|
|
|
int *fds;
|
|
|
|
|
unsigned nfd;
|
2011-10-24 03:33:11 +02:00
|
|
|
|
unsigned port;
|
2006-12-01 21:26:05 +01:00
|
|
|
|
|
2009-01-17 17:42:38 +01:00
|
|
|
|
vlc_thread_t thread;
|
2006-12-01 21:26:05 +01:00
|
|
|
|
vlc_mutex_t lock;
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_cond_t wait;
|
2006-12-01 21:26:05 +01:00
|
|
|
|
|
|
|
|
|
/* all registered url (becarefull that 2 httpd_url_t could point at the same url)
|
|
|
|
|
* This will slow down the url research but make my live easier
|
|
|
|
|
* All url will have their cb trigger, but only the first one can answer
|
|
|
|
|
* */
|
|
|
|
|
int i_url;
|
|
|
|
|
httpd_url_t **url;
|
|
|
|
|
|
|
|
|
|
int i_client;
|
|
|
|
|
httpd_client_t **client;
|
|
|
|
|
|
|
|
|
|
/* TLS data */
|
2011-07-23 13:28:28 +02:00
|
|
|
|
vlc_tls_creds_t *p_tls;
|
2006-12-01 21:26:05 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
struct httpd_url_t
|
|
|
|
|
{
|
|
|
|
|
httpd_host_t *host;
|
|
|
|
|
|
|
|
|
|
vlc_mutex_t lock;
|
|
|
|
|
|
2005-07-12 18:00:43 +02:00
|
|
|
|
char *psz_url;
|
|
|
|
|
char *psz_user;
|
|
|
|
|
char *psz_password;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
httpd_callback_t cb;
|
|
|
|
|
httpd_callback_sys_t *p_sys;
|
|
|
|
|
} catch[HTTPD_MSG_MAX];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* status */
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
HTTPD_CLIENT_RECEIVING,
|
|
|
|
|
HTTPD_CLIENT_RECEIVE_DONE,
|
|
|
|
|
|
|
|
|
|
HTTPD_CLIENT_SENDING,
|
|
|
|
|
HTTPD_CLIENT_SEND_DONE,
|
|
|
|
|
|
|
|
|
|
HTTPD_CLIENT_WAITING,
|
|
|
|
|
|
|
|
|
|
HTTPD_CLIENT_DEAD,
|
2004-12-25 22:35:09 +01:00
|
|
|
|
|
|
|
|
|
HTTPD_CLIENT_TLS_HS_IN,
|
|
|
|
|
HTTPD_CLIENT_TLS_HS_OUT
|
2004-03-03 14:23:47 +01:00
|
|
|
|
};
|
2006-02-04 20:48:38 +01:00
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* mode */
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
HTTPD_CLIENT_FILE, /* default */
|
|
|
|
|
HTTPD_CLIENT_STREAM, /* regulary get data from cb */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct httpd_client_t
|
|
|
|
|
{
|
|
|
|
|
httpd_url_t *url;
|
|
|
|
|
|
|
|
|
|
int i_ref;
|
|
|
|
|
|
|
|
|
|
int fd;
|
|
|
|
|
|
2011-11-03 18:41:56 +01:00
|
|
|
|
bool b_stream_mode;
|
|
|
|
|
uint8_t i_state;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
mtime_t i_activity_date;
|
|
|
|
|
mtime_t i_activity_timeout;
|
|
|
|
|
|
|
|
|
|
/* buffer for reading header */
|
|
|
|
|
int i_buffer_size;
|
|
|
|
|
int i_buffer;
|
|
|
|
|
uint8_t *p_buffer;
|
|
|
|
|
|
2013-08-16 16:42:40 +02:00
|
|
|
|
/*
|
|
|
|
|
* If waiting for a keyframe, this is the position (in bytes) of the
|
|
|
|
|
* last keyframe the stream saw before this client connected.
|
|
|
|
|
* Otherwise, -1.
|
|
|
|
|
*/
|
|
|
|
|
int64_t i_keyframe_wait_to_pass;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* */
|
|
|
|
|
httpd_message_t query; /* client -> httpd */
|
|
|
|
|
httpd_message_t answer; /* httpd -> client */
|
2006-02-04 20:48:38 +01:00
|
|
|
|
|
2004-11-04 23:55:54 +01:00
|
|
|
|
/* TLS data */
|
2011-07-23 13:28:28 +02:00
|
|
|
|
vlc_tls_t *p_tls;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* Various functions
|
|
|
|
|
*****************************************************************************/
|
2007-08-22 18:19:36 +02:00
|
|
|
|
static const char *httpd_ReasonFromCode( unsigned i_code )
|
2006-03-04 11:46:27 +01:00
|
|
|
|
{
|
2014-02-16 11:36:33 +01:00
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
unsigned i_code;
|
|
|
|
|
const char psz_reason[36];
|
|
|
|
|
} http_status_info;
|
|
|
|
|
|
|
|
|
|
static const http_status_info http_reason[] =
|
|
|
|
|
{
|
|
|
|
|
/*{ 100, "Continue" },
|
|
|
|
|
{ 101, "Switching Protocols" },*/
|
|
|
|
|
{ 200, "OK" },
|
|
|
|
|
/*{ 201, "Created" },
|
|
|
|
|
{ 202, "Accepted" },
|
|
|
|
|
{ 203, "Non-authoritative information" },
|
|
|
|
|
{ 204, "No content" },
|
|
|
|
|
{ 205, "Reset content" },
|
|
|
|
|
{ 206, "Partial content" },
|
|
|
|
|
{ 250, "Low on storage space" },
|
|
|
|
|
{ 300, "Multiple choices" },*/
|
|
|
|
|
{ 301, "Moved permanently" },
|
|
|
|
|
/*{ 302, "Moved temporarily" },
|
|
|
|
|
{ 303, "See other" },
|
|
|
|
|
{ 304, "Not modified" },
|
|
|
|
|
{ 305, "Use proxy" },
|
|
|
|
|
{ 307, "Temporary redirect" },
|
|
|
|
|
{ 400, "Bad request" },*/
|
|
|
|
|
{ 401, "Unauthorized" },
|
|
|
|
|
/*{ 402, "Payment Required" },*/
|
|
|
|
|
{ 403, "Forbidden" },
|
|
|
|
|
{ 404, "Not found" },
|
|
|
|
|
{ 405, "Method not allowed" },
|
|
|
|
|
/*{ 406, "Not acceptable" },
|
|
|
|
|
{ 407, "Proxy authentication required" },
|
|
|
|
|
{ 408, "Request time-out" },
|
|
|
|
|
{ 409, "Conflict" },
|
|
|
|
|
{ 410, "Gone" },
|
|
|
|
|
{ 411, "Length required" },
|
|
|
|
|
{ 412, "Precondition failed" },
|
|
|
|
|
{ 413, "Request entity too large" },
|
|
|
|
|
{ 414, "Request-URI too large" },
|
|
|
|
|
{ 415, "Unsupported media Type" },
|
|
|
|
|
{ 416, "Requested range not satisfiable" },
|
|
|
|
|
{ 417, "Expectation failed" },
|
|
|
|
|
{ 451, "Parameter not understood" },
|
|
|
|
|
{ 452, "Conference not found" },
|
|
|
|
|
{ 453, "Not enough bandwidth" },*/
|
|
|
|
|
{ 454, "Session not found" },
|
|
|
|
|
{ 455, "Method not valid in this State" },
|
|
|
|
|
{ 456, "Header field not valid for resource" },
|
|
|
|
|
{ 457, "Invalid range" },
|
|
|
|
|
/*{ 458, "Read-only parameter" },*/
|
|
|
|
|
{ 459, "Aggregate operation not allowed" },
|
|
|
|
|
{ 460, "Non-aggregate operation not allowed" },
|
|
|
|
|
{ 461, "Unsupported transport" },
|
|
|
|
|
/*{ 462, "Destination unreachable" },*/
|
|
|
|
|
{ 500, "Internal server error" },
|
|
|
|
|
{ 501, "Not implemented" },
|
|
|
|
|
/*{ 502, "Bad gateway" },*/
|
|
|
|
|
{ 503, "Service unavailable" },
|
|
|
|
|
/*{ 504, "Gateway time-out" },*/
|
|
|
|
|
{ 505, "Protocol version not supported" },
|
|
|
|
|
{ 551, "Option not supported" },
|
|
|
|
|
{ 999, "" }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char psz_fallback_reason[5][16] = {
|
|
|
|
|
"Continue", "OK", "Found", "Client error", "Server error"
|
|
|
|
|
};
|
2006-03-04 11:46:27 +01:00
|
|
|
|
|
2007-08-22 18:19:36 +02:00
|
|
|
|
assert( ( i_code >= 100 ) && ( i_code <= 599 ) );
|
|
|
|
|
|
2014-02-16 11:36:33 +01:00
|
|
|
|
const http_status_info *p = http_reason;
|
|
|
|
|
while (i_code < p->i_code)
|
|
|
|
|
p++;
|
2006-03-04 11:46:27 +01:00
|
|
|
|
|
2014-02-16 11:36:33 +01:00
|
|
|
|
if (p->i_code == i_code)
|
2006-03-04 11:46:27 +01:00
|
|
|
|
return p->psz_reason;
|
|
|
|
|
|
|
|
|
|
return psz_fallback_reason[(i_code / 100) - 1];
|
|
|
|
|
}
|
2006-11-24 16:46:43 +01:00
|
|
|
|
|
|
|
|
|
static size_t httpd_HtmlError (char **body, int code, const char *url)
|
|
|
|
|
{
|
|
|
|
|
const char *errname = httpd_ReasonFromCode (code);
|
|
|
|
|
assert (errname != NULL);
|
|
|
|
|
|
|
|
|
|
int res = asprintf (body,
|
|
|
|
|
"<?xml version=\"1.0\" encoding=\"ascii\" ?>\n"
|
|
|
|
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""
|
|
|
|
|
" \"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
|
|
|
|
|
"<html lang=\"en\">\n"
|
|
|
|
|
"<head>\n"
|
|
|
|
|
"<title>%s</title>\n"
|
|
|
|
|
"</head>\n"
|
|
|
|
|
"<body>\n"
|
|
|
|
|
"<h1>%d %s%s%s%s</h1>\n"
|
|
|
|
|
"<hr />\n"
|
|
|
|
|
"<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
|
|
|
|
|
"</body>\n"
|
|
|
|
|
"</html>\n", errname, code, errname,
|
2009-05-17 10:16:03 +02:00
|
|
|
|
(url ? " (" : ""), (url ? url : ""), (url ? ")" : ""));
|
2006-11-24 16:46:43 +01:00
|
|
|
|
|
|
|
|
|
if (res == -1)
|
|
|
|
|
{
|
|
|
|
|
*body = NULL;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (size_t)res;
|
|
|
|
|
}
|
|
|
|
|
|
2006-03-04 11:46:27 +01:00
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/*****************************************************************************
|
2005-08-26 20:15:21 +02:00
|
|
|
|
* High Level Functions: httpd_file_t
|
2004-03-03 14:23:47 +01:00
|
|
|
|
*****************************************************************************/
|
|
|
|
|
struct httpd_file_t
|
|
|
|
|
{
|
|
|
|
|
httpd_url_t *url;
|
|
|
|
|
|
|
|
|
|
char *psz_url;
|
|
|
|
|
char *psz_mime;
|
|
|
|
|
|
|
|
|
|
httpd_file_callback_t pf_fill;
|
|
|
|
|
httpd_file_sys_t *p_sys;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2007-08-30 23:29:51 +02:00
|
|
|
|
static int
|
|
|
|
|
httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl,
|
|
|
|
|
httpd_message_t *answer, const httpd_message_t *query )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_file_t *file = (httpd_file_t*)p_sys;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
uint8_t **pp_body, *p_body;
|
2006-11-24 16:16:18 +01:00
|
|
|
|
const char *psz_connection;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
int *pi_body, i_body;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
if( answer == NULL || query == NULL )
|
|
|
|
|
{
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
answer->i_proto = HTTPD_PROTO_HTTP;
|
2007-09-02 11:06:57 +02:00
|
|
|
|
answer->i_version= 1;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
|
|
|
|
|
answer->i_status = 200;
|
|
|
|
|
|
|
|
|
|
httpd_MsgAdd( answer, "Content-type", "%s", file->psz_mime );
|
|
|
|
|
httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
|
|
|
|
|
|
|
|
|
|
if( query->i_type != HTTPD_MSG_HEAD )
|
|
|
|
|
{
|
2005-08-26 20:15:21 +02:00
|
|
|
|
pp_body = &answer->p_body;
|
|
|
|
|
pi_body = &answer->i_body;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* The file still needs to be executed. */
|
|
|
|
|
p_body = NULL;
|
|
|
|
|
i_body = 0;
|
|
|
|
|
pp_body = &p_body;
|
|
|
|
|
pi_body = &i_body;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2005-08-26 20:15:21 +02:00
|
|
|
|
|
|
|
|
|
if( query->i_type == HTTPD_MSG_POST )
|
|
|
|
|
{
|
|
|
|
|
/* msg_Warn not supported */
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-30 17:56:42 +02:00
|
|
|
|
uint8_t *psz_args = query->psz_args;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
file->pf_fill( file->p_sys, file, psz_args, pp_body, pi_body );
|
|
|
|
|
|
|
|
|
|
if( query->i_type == HTTPD_MSG_HEAD && p_body != NULL )
|
|
|
|
|
{
|
|
|
|
|
free( p_body );
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-06 02:14:28 +01:00
|
|
|
|
/* We respect client request */
|
2006-03-22 22:01:09 +01:00
|
|
|
|
psz_connection = httpd_MsgGet( &cl->query, "Connection" );
|
|
|
|
|
if( psz_connection != NULL )
|
2004-03-06 02:14:28 +01:00
|
|
|
|
{
|
2007-12-23 18:42:57 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Connection", "%s", psz_connection );
|
2004-03-06 02:14:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
|
|
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
httpd_file_t *httpd_FileNew( httpd_host_t *host,
|
2005-08-04 16:58:44 +02:00
|
|
|
|
const char *psz_url, const char *psz_mime,
|
|
|
|
|
const char *psz_user, const char *psz_password,
|
2012-04-01 22:03:23 +02:00
|
|
|
|
httpd_file_callback_t pf_fill,
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_file_sys_t *p_sys )
|
|
|
|
|
{
|
2009-12-06 09:53:24 +01:00
|
|
|
|
httpd_file_t *file = xmalloc( sizeof( httpd_file_t ) );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2012-04-01 22:03:23 +02:00
|
|
|
|
file->url = httpd_UrlNew( host, psz_url, psz_user, psz_password );
|
2012-04-01 21:13:54 +02:00
|
|
|
|
if( file->url == NULL )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
free( file );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file->psz_url = strdup( psz_url );
|
|
|
|
|
if( psz_mime && *psz_mime )
|
|
|
|
|
{
|
|
|
|
|
file->psz_mime = strdup( psz_mime );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2012-08-28 18:07:06 +02:00
|
|
|
|
file->psz_mime = strdup( vlc_mime_Ext2Mime( psz_url ) );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file->pf_fill = pf_fill;
|
|
|
|
|
file->p_sys = p_sys;
|
|
|
|
|
|
2004-03-09 21:46:43 +01:00
|
|
|
|
httpd_UrlCatch( file->url, HTTPD_MSG_HEAD, httpd_FileCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)file );
|
|
|
|
|
httpd_UrlCatch( file->url, HTTPD_MSG_GET, httpd_FileCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)file );
|
|
|
|
|
httpd_UrlCatch( file->url, HTTPD_MSG_POST, httpd_FileCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)file );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
return file;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-07 20:36:02 +01:00
|
|
|
|
httpd_file_sys_t *httpd_FileDelete( httpd_file_t *file )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2007-11-07 20:36:02 +01:00
|
|
|
|
httpd_file_sys_t *p_sys = file->p_sys;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_UrlDelete( file->url );
|
|
|
|
|
|
|
|
|
|
free( file->psz_url );
|
|
|
|
|
free( file->psz_mime );
|
|
|
|
|
|
|
|
|
|
free( file );
|
2007-11-07 20:36:02 +01:00
|
|
|
|
|
|
|
|
|
return p_sys;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-08-26 20:15:21 +02:00
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* High Level Functions: httpd_handler_t (for CGIs)
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
struct httpd_handler_t
|
|
|
|
|
{
|
|
|
|
|
httpd_url_t *url;
|
|
|
|
|
|
|
|
|
|
httpd_handler_callback_t pf_fill;
|
|
|
|
|
httpd_handler_sys_t *p_sys;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2007-08-30 23:29:51 +02:00
|
|
|
|
static int
|
|
|
|
|
httpd_HandlerCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl,
|
|
|
|
|
httpd_message_t *answer, const httpd_message_t *query )
|
2005-08-26 20:15:21 +02:00
|
|
|
|
{
|
|
|
|
|
httpd_handler_t *handler = (httpd_handler_t*)p_sys;
|
2006-03-02 23:39:03 +01:00
|
|
|
|
char psz_remote_addr[NI_MAXNUMERICHOST];
|
2005-08-26 20:15:21 +02:00
|
|
|
|
|
|
|
|
|
if( answer == NULL || query == NULL )
|
|
|
|
|
{
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
answer->i_proto = HTTPD_PROTO_NONE;
|
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
|
|
|
|
|
/* We do it ourselves, thanks */
|
|
|
|
|
answer->i_status = 0;
|
|
|
|
|
|
2011-08-02 18:00:46 +02:00
|
|
|
|
if( httpd_ClientIP( cl, psz_remote_addr, NULL ) == NULL )
|
2006-03-02 23:39:03 +01:00
|
|
|
|
*psz_remote_addr = '\0';
|
2005-08-26 20:15:21 +02:00
|
|
|
|
|
2008-05-30 17:56:42 +02:00
|
|
|
|
uint8_t *psz_args = query->psz_args;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
handler->pf_fill( handler->p_sys, handler, query->psz_url, psz_args,
|
|
|
|
|
query->i_type, query->p_body, query->i_body,
|
|
|
|
|
psz_remote_addr, NULL,
|
|
|
|
|
&answer->p_body, &answer->i_body );
|
|
|
|
|
|
|
|
|
|
if( query->i_type == HTTPD_MSG_HEAD )
|
|
|
|
|
{
|
2006-02-01 14:28:59 +01:00
|
|
|
|
char *p = (char *)answer->p_body;
|
2007-09-15 15:43:38 +02:00
|
|
|
|
|
|
|
|
|
/* Looks for end of header (i.e. one empty line) */
|
2005-08-26 20:15:21 +02:00
|
|
|
|
while ( (p = strchr( p, '\r' )) != NULL )
|
|
|
|
|
{
|
|
|
|
|
if( p[1] && p[1] == '\n' && p[2] && p[2] == '\r'
|
|
|
|
|
&& p[3] && p[3] == '\n' )
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-15 15:43:38 +02:00
|
|
|
|
|
2005-08-26 20:15:21 +02:00
|
|
|
|
if( p != NULL )
|
|
|
|
|
{
|
|
|
|
|
p[4] = '\0';
|
2006-02-01 14:28:59 +01:00
|
|
|
|
answer->i_body = strlen((char*)answer->p_body) + 1;
|
2009-12-06 09:40:55 +01:00
|
|
|
|
answer->p_body = xrealloc( answer->p_body, answer->i_body );
|
2005-08-26 20:15:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-01 14:28:59 +01:00
|
|
|
|
if( strncmp( (char *)answer->p_body, "HTTP/1.", 7 ) )
|
2005-08-26 20:15:21 +02:00
|
|
|
|
{
|
|
|
|
|
int i_status, i_headers;
|
2006-11-24 16:16:18 +01:00
|
|
|
|
char *psz_headers, *psz_new;
|
|
|
|
|
const char *psz_status;
|
2006-02-01 14:28:59 +01:00
|
|
|
|
|
|
|
|
|
if( !strncmp( (char *)answer->p_body, "Status: ", 8 ) )
|
2005-08-26 20:15:21 +02:00
|
|
|
|
{
|
|
|
|
|
/* Apache-style */
|
2006-02-01 14:28:59 +01:00
|
|
|
|
i_status = strtol( (char *)&answer->p_body[8], &psz_headers, 0 );
|
2009-12-21 23:52:47 +01:00
|
|
|
|
if( *psz_headers == '\r' || *psz_headers == '\n' ) psz_headers++;
|
|
|
|
|
if( *psz_headers == '\n' ) psz_headers++;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
i_headers = answer->i_body - (psz_headers - (char *)answer->p_body);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
i_status = 200;
|
2006-02-01 14:28:59 +01:00
|
|
|
|
psz_headers = (char *)answer->p_body;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
i_headers = answer->i_body;
|
|
|
|
|
}
|
2007-08-21 21:11:34 +02:00
|
|
|
|
|
|
|
|
|
psz_status = httpd_ReasonFromCode( i_status );
|
2006-02-01 14:28:59 +01:00
|
|
|
|
answer->i_body = sizeof("HTTP/1.0 xxx \r\n")
|
|
|
|
|
+ strlen(psz_status) + i_headers - 1;
|
2009-12-06 09:53:24 +01:00
|
|
|
|
psz_new = (char *)xmalloc( answer->i_body + 1);
|
2006-02-01 14:28:59 +01:00
|
|
|
|
sprintf( psz_new, "HTTP/1.0 %03d %s\r\n", i_status, psz_status );
|
2005-08-26 20:15:21 +02:00
|
|
|
|
memcpy( &psz_new[strlen(psz_new)], psz_headers, i_headers );
|
|
|
|
|
free( answer->p_body );
|
2006-02-01 14:28:59 +01:00
|
|
|
|
answer->p_body = (uint8_t *)psz_new;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
httpd_handler_t *httpd_HandlerNew( httpd_host_t *host, const char *psz_url,
|
|
|
|
|
const char *psz_user,
|
|
|
|
|
const char *psz_password,
|
|
|
|
|
httpd_handler_callback_t pf_fill,
|
|
|
|
|
httpd_handler_sys_t *p_sys )
|
|
|
|
|
{
|
2009-12-06 09:53:24 +01:00
|
|
|
|
httpd_handler_t *handler = xmalloc( sizeof( httpd_handler_t ) );
|
2005-08-26 20:15:21 +02:00
|
|
|
|
|
2012-04-01 22:03:23 +02:00
|
|
|
|
handler->url = httpd_UrlNew( host, psz_url, psz_user, psz_password );
|
2012-04-01 21:13:54 +02:00
|
|
|
|
if( handler->url == NULL )
|
2005-08-26 20:15:21 +02:00
|
|
|
|
{
|
|
|
|
|
free( handler );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handler->pf_fill = pf_fill;
|
|
|
|
|
handler->p_sys = p_sys;
|
|
|
|
|
|
|
|
|
|
httpd_UrlCatch( handler->url, HTTPD_MSG_HEAD, httpd_HandlerCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)handler );
|
|
|
|
|
httpd_UrlCatch( handler->url, HTTPD_MSG_GET, httpd_HandlerCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)handler );
|
|
|
|
|
httpd_UrlCatch( handler->url, HTTPD_MSG_POST, httpd_HandlerCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)handler );
|
|
|
|
|
|
|
|
|
|
return handler;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-07 20:36:02 +01:00
|
|
|
|
httpd_handler_sys_t *httpd_HandlerDelete( httpd_handler_t *handler )
|
2005-08-26 20:15:21 +02:00
|
|
|
|
{
|
2007-11-07 20:36:02 +01:00
|
|
|
|
httpd_handler_sys_t *p_sys = handler->p_sys;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
httpd_UrlDelete( handler->url );
|
|
|
|
|
free( handler );
|
2007-11-07 20:36:02 +01:00
|
|
|
|
return p_sys;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/*****************************************************************************
|
2005-08-12 21:11:54 +02:00
|
|
|
|
* High Level Functions: httpd_redirect_t
|
2004-03-03 14:23:47 +01:00
|
|
|
|
*****************************************************************************/
|
|
|
|
|
struct httpd_redirect_t
|
|
|
|
|
{
|
|
|
|
|
httpd_url_t *url;
|
|
|
|
|
char *psz_dst;
|
|
|
|
|
};
|
|
|
|
|
|
2004-03-09 21:46:43 +01:00
|
|
|
|
static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys,
|
|
|
|
|
httpd_client_t *cl, httpd_message_t *answer,
|
2007-08-30 23:29:51 +02:00
|
|
|
|
const httpd_message_t *query )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_redirect_t *rdir = (httpd_redirect_t*)p_sys;
|
2006-09-03 17:08:52 +02:00
|
|
|
|
char *p_body;
|
2007-04-05 18:42:16 +02:00
|
|
|
|
(void)cl;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
if( answer == NULL || query == NULL )
|
|
|
|
|
{
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
2007-09-02 10:51:01 +02:00
|
|
|
|
answer->i_proto = HTTPD_PROTO_HTTP;
|
2007-09-02 11:06:57 +02:00
|
|
|
|
answer->i_version= 1;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
answer->i_status = 301;
|
|
|
|
|
|
2006-11-24 16:46:43 +01:00
|
|
|
|
answer->i_body = httpd_HtmlError (&p_body, 301, rdir->psz_dst);
|
2006-09-03 17:08:52 +02:00
|
|
|
|
answer->p_body = (unsigned char *)p_body;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
/* XXX check if it's ok or we need to set an absolute url */
|
|
|
|
|
httpd_MsgAdd( answer, "Location", "%s", rdir->psz_dst );
|
|
|
|
|
|
|
|
|
|
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
|
|
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-04 16:58:44 +02:00
|
|
|
|
httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, const char *psz_url_dst,
|
|
|
|
|
const char *psz_url_src )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2009-12-06 09:53:24 +01:00
|
|
|
|
httpd_redirect_t *rdir = xmalloc( sizeof( httpd_redirect_t ) );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2012-04-01 21:13:54 +02:00
|
|
|
|
rdir->url = httpd_UrlNew( host, psz_url_src, NULL, NULL );
|
|
|
|
|
if( rdir->url == NULL )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
free( rdir );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
rdir->psz_dst = strdup( psz_url_dst );
|
|
|
|
|
|
2004-03-09 21:46:43 +01:00
|
|
|
|
/* Redirect apply for all HTTP request and RTSP DESCRIBE resquest */
|
|
|
|
|
httpd_UrlCatch( rdir->url, HTTPD_MSG_HEAD, httpd_RedirectCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)rdir );
|
|
|
|
|
httpd_UrlCatch( rdir->url, HTTPD_MSG_GET, httpd_RedirectCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)rdir );
|
|
|
|
|
httpd_UrlCatch( rdir->url, HTTPD_MSG_POST, httpd_RedirectCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)rdir );
|
|
|
|
|
httpd_UrlCatch( rdir->url, HTTPD_MSG_DESCRIBE, httpd_RedirectCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)rdir );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
return rdir;
|
|
|
|
|
}
|
2004-03-09 21:46:43 +01:00
|
|
|
|
void httpd_RedirectDelete( httpd_redirect_t *rdir )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_UrlDelete( rdir->url );
|
|
|
|
|
free( rdir->psz_dst );
|
|
|
|
|
free( rdir );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* High Level Funtions: httpd_stream_t
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
struct httpd_stream_t
|
|
|
|
|
{
|
|
|
|
|
vlc_mutex_t lock;
|
|
|
|
|
httpd_url_t *url;
|
|
|
|
|
|
|
|
|
|
char *psz_mime;
|
|
|
|
|
|
|
|
|
|
/* Header to send as first packet */
|
|
|
|
|
uint8_t *p_header;
|
|
|
|
|
int i_header;
|
|
|
|
|
|
2013-08-16 16:42:40 +02:00
|
|
|
|
/* Some muxes, in particular the avformat mux, can mark given blocks
|
|
|
|
|
* as keyframes, to ensure that the stream starts with one.
|
|
|
|
|
* (This is particularly important for WebM streaming to certain
|
|
|
|
|
* browsers.) Store if we've ever seen any such keyframe blocks,
|
|
|
|
|
* and if so, the byte position of the start of the last one. */
|
|
|
|
|
bool b_has_keyframes;
|
|
|
|
|
int64_t i_last_keyframe_seen_pos;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* circular buffer */
|
|
|
|
|
int i_buffer_size; /* buffer size, can't be reallocated smaller */
|
|
|
|
|
uint8_t *p_buffer; /* buffer */
|
|
|
|
|
int64_t i_buffer_pos; /* absolute position from begining */
|
|
|
|
|
int64_t i_buffer_last_pos; /* a new connection will start with that */
|
2014-02-15 23:15:49 +01:00
|
|
|
|
|
|
|
|
|
/* custom headers */
|
|
|
|
|
size_t i_http_headers;
|
|
|
|
|
httpd_header * p_http_headers;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
};
|
|
|
|
|
|
2004-03-08 16:55:49 +01:00
|
|
|
|
static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
|
|
|
|
|
httpd_client_t *cl, httpd_message_t *answer,
|
2007-08-30 23:29:51 +02:00
|
|
|
|
const httpd_message_t *query )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_stream_t *stream = (httpd_stream_t*)p_sys;
|
|
|
|
|
|
|
|
|
|
if( answer == NULL || query == NULL || cl == NULL )
|
|
|
|
|
{
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
2006-02-04 20:48:38 +01:00
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( answer->i_body_offset > 0 )
|
|
|
|
|
{
|
|
|
|
|
int64_t i_write;
|
|
|
|
|
int i_pos;
|
|
|
|
|
|
2004-03-08 16:55:49 +01:00
|
|
|
|
#if 0
|
|
|
|
|
fprintf( stderr, "httpd_StreamCallBack i_body_offset=%lld\n",
|
|
|
|
|
answer->i_body_offset );
|
|
|
|
|
#endif
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
if( answer->i_body_offset >= stream->i_buffer_pos )
|
|
|
|
|
{
|
|
|
|
|
/* fprintf( stderr, "httpd_StreamCallBack: no data\n" ); */
|
|
|
|
|
return VLC_EGENERIC; /* wait, no data available */
|
|
|
|
|
}
|
2013-08-16 16:42:40 +02:00
|
|
|
|
if( cl->i_keyframe_wait_to_pass >= 0 )
|
|
|
|
|
{
|
|
|
|
|
if( stream->i_last_keyframe_seen_pos <= cl->i_keyframe_wait_to_pass )
|
|
|
|
|
/* still waiting for the next keyframe */
|
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
|
|
/* seek to the new keyframe */
|
|
|
|
|
answer->i_body_offset = stream->i_last_keyframe_seen_pos;
|
|
|
|
|
cl->i_keyframe_wait_to_pass = -1;
|
|
|
|
|
}
|
2004-03-08 16:55:49 +01:00
|
|
|
|
if( answer->i_body_offset + stream->i_buffer_size <
|
|
|
|
|
stream->i_buffer_pos )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
/* this client isn't fast enough */
|
2006-03-04 11:46:27 +01:00
|
|
|
|
#if 0
|
2004-03-03 14:23:47 +01:00
|
|
|
|
fprintf( stderr, "fixing i_body_offset (old=%lld new=%lld)\n",
|
|
|
|
|
answer->i_body_offset, stream->i_buffer_last_pos );
|
2006-03-04 11:46:27 +01:00
|
|
|
|
#endif
|
2004-03-03 14:23:47 +01:00
|
|
|
|
answer->i_body_offset = stream->i_buffer_last_pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i_pos = answer->i_body_offset % stream->i_buffer_size;
|
|
|
|
|
i_write = stream->i_buffer_pos - answer->i_body_offset;
|
2005-10-22 18:23:01 +02:00
|
|
|
|
if( i_write > HTTPD_CL_BUFSIZE )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2005-10-22 18:23:01 +02:00
|
|
|
|
i_write = HTTPD_CL_BUFSIZE;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
else if( i_write <= 0 )
|
|
|
|
|
{
|
|
|
|
|
return VLC_EGENERIC; /* wait, no data available */
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-08 16:55:49 +01:00
|
|
|
|
/* Don't go past the end of the circular buffer */
|
|
|
|
|
i_write = __MIN( i_write, stream->i_buffer_size - i_pos );
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* using HTTPD_MSG_ANSWER -> data available */
|
|
|
|
|
answer->i_proto = HTTPD_PROTO_HTTP;
|
|
|
|
|
answer->i_version= 0;
|
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
|
|
|
|
|
answer->i_body = i_write;
|
2009-12-06 09:53:24 +01:00
|
|
|
|
answer->p_body = xmalloc( i_write );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
memcpy( answer->p_body, &stream->p_buffer[i_pos], i_write );
|
|
|
|
|
|
|
|
|
|
answer->i_body_offset += i_write;
|
|
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
answer->i_proto = HTTPD_PROTO_HTTP;
|
|
|
|
|
answer->i_version= 0;
|
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
|
|
|
|
|
answer->i_status = 200;
|
|
|
|
|
|
2014-02-15 23:15:49 +01:00
|
|
|
|
bool b_has_content_type = false;
|
|
|
|
|
bool b_has_cache_control = false;
|
|
|
|
|
|
|
|
|
|
vlc_mutex_lock( &stream->lock );
|
|
|
|
|
for( size_t i = 0; i < stream->i_http_headers; i++ )
|
|
|
|
|
{
|
|
|
|
|
if( strncasecmp( stream->p_http_headers[i].name, "Content-Length", 14 ) )
|
|
|
|
|
{
|
|
|
|
|
httpd_MsgAdd( answer, stream->p_http_headers[i].name,
|
|
|
|
|
stream->p_http_headers[i].value );
|
|
|
|
|
|
|
|
|
|
if( !strncasecmp( stream->p_http_headers[i].name, "Content-Type", 12 ) )
|
|
|
|
|
b_has_content_type = true;
|
|
|
|
|
else if( !strncasecmp( stream->p_http_headers[i].name, "Cache-Control", 13 ) )
|
|
|
|
|
b_has_cache_control = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
vlc_mutex_unlock( &stream->lock );
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( query->i_type != HTTPD_MSG_HEAD )
|
|
|
|
|
{
|
2011-11-03 18:41:56 +01:00
|
|
|
|
cl->b_stream_mode = true;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
vlc_mutex_lock( &stream->lock );
|
|
|
|
|
/* Send the header */
|
|
|
|
|
if( stream->i_header > 0 )
|
|
|
|
|
{
|
|
|
|
|
answer->i_body = stream->i_header;
|
2009-12-06 09:53:24 +01:00
|
|
|
|
answer->p_body = xmalloc( stream->i_header );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
memcpy( answer->p_body, stream->p_header, stream->i_header );
|
|
|
|
|
}
|
|
|
|
|
answer->i_body_offset = stream->i_buffer_last_pos;
|
2013-08-16 16:42:40 +02:00
|
|
|
|
if( stream->b_has_keyframes )
|
|
|
|
|
cl->i_keyframe_wait_to_pass = stream->i_last_keyframe_seen_pos;
|
|
|
|
|
else
|
|
|
|
|
cl->i_keyframe_wait_to_pass = -1;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
vlc_mutex_unlock( &stream->lock );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-02-15 23:15:49 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Content-Length", "0" );
|
2004-04-19 10:27:34 +02:00
|
|
|
|
answer->i_body_offset = 0;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-15 23:15:49 +01:00
|
|
|
|
/* FIXME: move to http access_output */
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) )
|
|
|
|
|
{
|
2008-04-14 00:08:29 +02:00
|
|
|
|
bool b_xplaystream = false;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
int i;
|
|
|
|
|
|
2014-02-15 23:15:49 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Content-type", "application/octet-stream" );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" );
|
|
|
|
|
httpd_MsgAdd( answer, "Pragma", "no-cache" );
|
2010-03-06 11:21:02 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Pragma", "client-id=%lu",
|
|
|
|
|
vlc_mrand48()&0x7fff );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" );
|
2004-04-19 10:27:34 +02:00
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* Check if there is a xPlayStrm=1 */
|
2014-02-15 23:15:49 +01:00
|
|
|
|
for( i = 0; i < query->i_headers; i++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-15 23:15:49 +01:00
|
|
|
|
if( !strcasecmp( query->p_headers[i].name, "Pragma" ) &&
|
|
|
|
|
strstr( query->p_headers[i].value, "xPlayStrm=1" ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2008-04-14 00:08:29 +02:00
|
|
|
|
b_xplaystream = true;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !b_xplaystream )
|
|
|
|
|
{
|
|
|
|
|
answer->i_body_offset = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-15 23:15:49 +01:00
|
|
|
|
else if( !b_has_content_type )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-15 23:15:49 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Content-type", stream->psz_mime );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2014-02-15 23:15:49 +01:00
|
|
|
|
if( !b_has_cache_control )
|
|
|
|
|
httpd_MsgAdd( answer, "Cache-Control", "no-cache" );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
|
2005-08-04 16:58:44 +02:00
|
|
|
|
const char *psz_url, const char *psz_mime,
|
2012-04-01 21:50:45 +02:00
|
|
|
|
const char *psz_user, const char *psz_password )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2009-12-06 09:53:24 +01:00
|
|
|
|
httpd_stream_t *stream = xmalloc( sizeof( httpd_stream_t ) );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2012-04-01 22:03:23 +02:00
|
|
|
|
stream->url = httpd_UrlNew( host, psz_url, psz_user, psz_password );
|
2012-04-01 21:13:54 +02:00
|
|
|
|
if( stream->url == NULL )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
free( stream );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2008-05-04 13:10:08 +02:00
|
|
|
|
vlc_mutex_init( &stream->lock );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( psz_mime && *psz_mime )
|
|
|
|
|
{
|
|
|
|
|
stream->psz_mime = strdup( psz_mime );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2012-08-28 18:07:06 +02:00
|
|
|
|
stream->psz_mime = strdup( vlc_mime_Ext2Mime( psz_url ) );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
stream->i_header = 0;
|
|
|
|
|
stream->p_header = NULL;
|
|
|
|
|
stream->i_buffer_size = 5000000; /* 5 Mo per stream */
|
2009-12-06 09:53:24 +01:00
|
|
|
|
stream->p_buffer = xmalloc( stream->i_buffer_size );
|
2004-03-09 21:46:43 +01:00
|
|
|
|
/* We set to 1 to make life simpler
|
|
|
|
|
* (this way i_body_offset can never be 0) */
|
2004-03-03 14:23:47 +01:00
|
|
|
|
stream->i_buffer_pos = 1;
|
|
|
|
|
stream->i_buffer_last_pos = 1;
|
2013-08-16 16:42:40 +02:00
|
|
|
|
stream->b_has_keyframes = false;
|
|
|
|
|
stream->i_last_keyframe_seen_pos = 0;
|
2014-02-15 23:15:49 +01:00
|
|
|
|
stream->i_http_headers = 0;
|
|
|
|
|
stream->p_http_headers = NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2004-03-09 21:46:43 +01:00
|
|
|
|
httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)stream );
|
|
|
|
|
httpd_UrlCatch( stream->url, HTTPD_MSG_GET, httpd_StreamCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)stream );
|
|
|
|
|
httpd_UrlCatch( stream->url, HTTPD_MSG_POST, httpd_StreamCallBack,
|
|
|
|
|
(httpd_callback_sys_t*)stream );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-09 21:46:43 +01:00
|
|
|
|
int httpd_StreamHeader( httpd_stream_t *stream, uint8_t *p_data, int i_data )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
vlc_mutex_lock( &stream->lock );
|
2008-03-12 00:30:25 +01:00
|
|
|
|
free( stream->p_header );
|
|
|
|
|
stream->p_header = NULL;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
stream->i_header = i_data;
|
|
|
|
|
if( i_data > 0 )
|
|
|
|
|
{
|
2009-12-06 09:53:24 +01:00
|
|
|
|
stream->p_header = xmalloc( i_data );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
memcpy( stream->p_header, p_data, i_data );
|
|
|
|
|
}
|
|
|
|
|
vlc_mutex_unlock( &stream->lock );
|
|
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-16 16:42:40 +02:00
|
|
|
|
static void httpd_AppendData( httpd_stream_t *stream, uint8_t *p_data, int i_data )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2013-08-16 16:42:40 +02:00
|
|
|
|
int i_pos = stream->i_buffer_pos % stream->i_buffer_size;
|
|
|
|
|
int i_count = i_data;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
while( i_count > 0)
|
|
|
|
|
{
|
|
|
|
|
int i_copy;
|
|
|
|
|
|
|
|
|
|
i_copy = __MIN( i_count, stream->i_buffer_size - i_pos );
|
|
|
|
|
|
|
|
|
|
/* Ok, we can't go past the end of our buffer */
|
|
|
|
|
memcpy( &stream->p_buffer[i_pos], p_data, i_copy );
|
|
|
|
|
|
|
|
|
|
i_pos = ( i_pos + i_copy ) % stream->i_buffer_size;
|
|
|
|
|
i_count -= i_copy;
|
|
|
|
|
p_data += i_copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stream->i_buffer_pos += i_data;
|
2013-08-16 16:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int httpd_StreamSend( httpd_stream_t *stream, const block_t *p_block )
|
|
|
|
|
{
|
|
|
|
|
if( p_block == NULL || p_block->p_buffer == NULL )
|
|
|
|
|
{
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
vlc_mutex_lock( &stream->lock );
|
|
|
|
|
|
|
|
|
|
/* save this pointer (to be used by new connection) */
|
|
|
|
|
stream->i_buffer_last_pos = stream->i_buffer_pos;
|
|
|
|
|
|
|
|
|
|
if( p_block->i_flags & BLOCK_FLAG_TYPE_I )
|
|
|
|
|
{
|
|
|
|
|
stream->b_has_keyframes = true;
|
|
|
|
|
stream->i_last_keyframe_seen_pos = stream->i_buffer_pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
httpd_AppendData( stream, p_block->p_buffer, p_block->i_buffer );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
vlc_mutex_unlock( &stream->lock );
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void httpd_StreamDelete( httpd_stream_t *stream )
|
|
|
|
|
{
|
|
|
|
|
httpd_UrlDelete( stream->url );
|
2014-02-15 23:15:49 +01:00
|
|
|
|
for( size_t i = 0; i < stream->i_http_headers; i++ )
|
|
|
|
|
{
|
|
|
|
|
free( stream->p_http_headers[i].name );
|
|
|
|
|
free( stream->p_http_headers[i].value );
|
|
|
|
|
}
|
|
|
|
|
free( stream->p_http_headers );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
vlc_mutex_destroy( &stream->lock );
|
2008-03-12 00:30:25 +01:00
|
|
|
|
free( stream->psz_mime );
|
|
|
|
|
free( stream->p_header );
|
|
|
|
|
free( stream->p_buffer );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
free( stream );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* Low level
|
|
|
|
|
*****************************************************************************/
|
2009-01-17 17:42:38 +01:00
|
|
|
|
static void* httpd_HostThread( void * );
|
2011-10-24 03:33:11 +02:00
|
|
|
|
static httpd_host_t *httpd_HostCreate( vlc_object_t *, const char *,
|
|
|
|
|
const char *, vlc_tls_creds_t * );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
/* create a new host */
|
2011-08-02 18:06:29 +02:00
|
|
|
|
httpd_host_t *vlc_http_HostNew( vlc_object_t *p_this )
|
2004-11-04 23:55:54 +01:00
|
|
|
|
{
|
2011-10-24 03:33:11 +02:00
|
|
|
|
return httpd_HostCreate( p_this, "http-host", "http-port", NULL );
|
2011-08-02 17:26:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-02 18:06:29 +02:00
|
|
|
|
httpd_host_t *vlc_https_HostNew( vlc_object_t *obj )
|
2011-08-02 17:26:40 +02:00
|
|
|
|
{
|
|
|
|
|
char *cert = var_InheritString( obj, "http-cert" );
|
|
|
|
|
if( cert == NULL )
|
|
|
|
|
{
|
|
|
|
|
msg_Err( obj, "HTTP/TLS certificate not specified!" );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *key = var_InheritString( obj, "http-key" );
|
|
|
|
|
vlc_tls_creds_t *tls = vlc_tls_ServerCreate( obj, cert, key );
|
|
|
|
|
|
|
|
|
|
if( tls == NULL )
|
|
|
|
|
{
|
|
|
|
|
msg_Err( obj, "HTTP/TLS certificate error (%s and %s)",
|
|
|
|
|
cert, (key != NULL) ? key : cert );
|
|
|
|
|
free( key );
|
|
|
|
|
free( cert );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
free( key );
|
|
|
|
|
free( cert );
|
|
|
|
|
|
|
|
|
|
char *ca = var_InheritString( obj, "http-ca" );
|
|
|
|
|
if( ca != NULL )
|
|
|
|
|
{
|
|
|
|
|
if( vlc_tls_ServerAddCA( tls, ca ) )
|
|
|
|
|
{
|
|
|
|
|
msg_Err( obj, "HTTP/TLS CA error (%s)", ca );
|
|
|
|
|
free( ca );
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
free( ca );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *crl = var_InheritString( obj, "http-crl" );
|
|
|
|
|
if( crl != NULL )
|
|
|
|
|
{
|
|
|
|
|
if( vlc_tls_ServerAddCRL( tls, crl ) )
|
|
|
|
|
{
|
|
|
|
|
msg_Err( obj, "TLS CRL error (%s)", crl );
|
|
|
|
|
free( crl );
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
free( crl );
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 03:33:11 +02:00
|
|
|
|
return httpd_HostCreate( obj, "http-host", "https-port", tls );
|
2011-08-02 17:26:40 +02:00
|
|
|
|
|
|
|
|
|
error:
|
2012-09-29 22:00:21 +02:00
|
|
|
|
vlc_tls_Delete( tls );
|
2011-08-02 17:26:40 +02:00
|
|
|
|
return NULL;
|
2004-11-04 23:55:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-02 18:06:29 +02:00
|
|
|
|
httpd_host_t *vlc_rtsp_HostNew( vlc_object_t *p_this )
|
2011-08-02 17:37:19 +02:00
|
|
|
|
{
|
2011-10-24 03:33:11 +02:00
|
|
|
|
return httpd_HostCreate( p_this, "rtsp-host", "rtsp-port", NULL );
|
2011-08-02 17:37:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-04-02 19:14:12 +02:00
|
|
|
|
static struct httpd
|
2011-10-24 03:33:11 +02:00
|
|
|
|
{
|
|
|
|
|
vlc_mutex_t mutex;
|
|
|
|
|
|
|
|
|
|
httpd_host_t **host;
|
|
|
|
|
int i_host;
|
|
|
|
|
} httpd = { VLC_STATIC_MUTEX, NULL, 0 };
|
|
|
|
|
|
2011-08-02 17:26:40 +02:00
|
|
|
|
static httpd_host_t *httpd_HostCreate( vlc_object_t *p_this,
|
2011-08-02 18:06:29 +02:00
|
|
|
|
const char *hostvar,
|
|
|
|
|
const char *portvar,
|
2011-08-02 17:26:40 +02:00
|
|
|
|
vlc_tls_creds_t *p_tls )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2005-05-22 13:36:59 +02:00
|
|
|
|
httpd_host_t *host;
|
2011-12-18 18:58:23 +01:00
|
|
|
|
char *hostname = var_InheritString( p_this, hostvar );
|
2011-10-24 03:33:11 +02:00
|
|
|
|
unsigned port = var_InheritInteger( p_this, portvar );
|
2004-07-17 14:30:59 +02:00
|
|
|
|
|
2011-12-18 18:58:23 +01:00
|
|
|
|
vlc_url_t url;
|
|
|
|
|
vlc_UrlParse( &url, hostname, 0 );
|
|
|
|
|
free( hostname );
|
|
|
|
|
if( url.i_port != 0 )
|
|
|
|
|
{
|
|
|
|
|
msg_Err( p_this, "Ignoring port %d (using %d)", url.i_port, port );
|
|
|
|
|
msg_Info( p_this, "Specify port %d separately with the "
|
|
|
|
|
"%s option instead.", url.i_port, portvar );
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* to be sure to avoid multiple creation */
|
2011-09-25 17:54:42 +02:00
|
|
|
|
vlc_mutex_lock( &httpd.mutex );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2005-05-22 13:36:59 +02:00
|
|
|
|
/* verify if it already exist */
|
2011-10-24 03:33:11 +02:00
|
|
|
|
for( int i = 0; i < httpd.i_host; i++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2011-10-24 03:33:11 +02:00
|
|
|
|
host = httpd.host[i];
|
|
|
|
|
|
|
|
|
|
/* cannot mix TLS and non-TLS hosts */
|
|
|
|
|
if( host->port != port
|
|
|
|
|
|| (host->p_tls != NULL) != (p_tls != NULL) )
|
|
|
|
|
continue;
|
|
|
|
|
|
2009-01-14 21:07:31 +01:00
|
|
|
|
/* Increase existing matching host reference count.
|
|
|
|
|
* The reference count is written under both the global httpd and the
|
|
|
|
|
* host lock. It is read with either or both locks held. The global
|
|
|
|
|
* lock is always acquired first. */
|
|
|
|
|
vlc_mutex_lock( &host->lock );
|
2005-05-22 13:36:59 +02:00
|
|
|
|
host->i_ref++;
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_mutex_unlock( &host->lock );
|
2004-07-17 14:30:59 +02:00
|
|
|
|
|
2011-09-25 17:54:42 +02:00
|
|
|
|
vlc_mutex_unlock( &httpd.mutex );
|
2011-12-18 18:58:23 +01:00
|
|
|
|
vlc_UrlClean( &url );
|
2012-09-29 22:00:21 +02:00
|
|
|
|
vlc_tls_Delete( p_tls );
|
2005-05-22 13:36:59 +02:00
|
|
|
|
return host;
|
2004-07-24 11:06:58 +02:00
|
|
|
|
}
|
2004-07-17 14:30:59 +02:00
|
|
|
|
|
|
|
|
|
/* create the new host */
|
2006-12-01 21:26:05 +01:00
|
|
|
|
host = (httpd_host_t *)vlc_custom_create( p_this, sizeof (*host),
|
2011-07-11 17:32:04 +02:00
|
|
|
|
"http host" );
|
2006-12-01 21:26:05 +01:00
|
|
|
|
if (host == NULL)
|
|
|
|
|
goto error;
|
|
|
|
|
|
2008-05-04 13:10:08 +02:00
|
|
|
|
vlc_mutex_init( &host->lock );
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_cond_init( &host->wait );
|
2004-07-17 14:30:59 +02:00
|
|
|
|
host->i_ref = 1;
|
|
|
|
|
|
2011-12-18 18:58:23 +01:00
|
|
|
|
host->fds = net_ListenTCP( p_this, url.psz_host, port );
|
2007-02-21 18:58:12 +01:00
|
|
|
|
if( host->fds == NULL )
|
2005-05-22 13:36:59 +02:00
|
|
|
|
{
|
|
|
|
|
msg_Err( p_this, "cannot create socket(s) for HTTP host" );
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
2007-02-21 18:58:12 +01:00
|
|
|
|
for (host->nfd = 0; host->fds[host->nfd] != -1; host->nfd++);
|
2006-02-10 15:43:05 +01:00
|
|
|
|
|
2009-01-14 20:58:51 +01:00
|
|
|
|
if( vlc_object_waitpipe( VLC_OBJECT( host ) ) == -1 )
|
|
|
|
|
{
|
2013-12-28 17:46:52 +01:00
|
|
|
|
msg_Err( host, "signaling pipe error: %s", vlc_strerror_c(errno) );
|
2009-01-14 20:58:51 +01:00
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 03:33:11 +02:00
|
|
|
|
host->port = port;
|
2011-08-02 18:06:29 +02:00
|
|
|
|
host->i_url = 0;
|
|
|
|
|
host->url = NULL;
|
|
|
|
|
host->i_client = 0;
|
|
|
|
|
host->client = NULL;
|
|
|
|
|
host->p_tls = p_tls;
|
2004-07-24 11:06:58 +02:00
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* create the thread */
|
2009-01-17 17:42:38 +01:00
|
|
|
|
if( vlc_clone( &host->thread, httpd_HostThread, host,
|
|
|
|
|
VLC_THREAD_PRIORITY_LOW ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
msg_Err( p_this, "cannot spawn http host thread" );
|
2004-07-17 14:30:59 +02:00
|
|
|
|
goto error;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 03:33:11 +02:00
|
|
|
|
/* now add it to httpd */
|
|
|
|
|
TAB_APPEND( httpd.i_host, httpd.host, host );
|
2011-09-25 17:54:42 +02:00
|
|
|
|
vlc_mutex_unlock( &httpd.mutex );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2011-12-18 18:58:23 +01:00
|
|
|
|
vlc_UrlClean( &url );
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
return host;
|
|
|
|
|
|
2004-07-17 14:30:59 +02:00
|
|
|
|
error:
|
2011-09-25 17:54:42 +02:00
|
|
|
|
vlc_mutex_unlock( &httpd.mutex );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2004-07-17 14:30:59 +02:00
|
|
|
|
if( host != NULL )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2007-02-21 18:58:12 +01:00
|
|
|
|
net_ListenClose( host->fds );
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_cond_destroy( &host->wait );
|
2004-07-17 14:30:59 +02:00
|
|
|
|
vlc_mutex_destroy( &host->lock );
|
2008-02-26 01:29:12 +01:00
|
|
|
|
vlc_object_release( host );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-12-18 18:58:23 +01:00
|
|
|
|
vlc_UrlClean( &url );
|
2012-09-29 22:00:21 +02:00
|
|
|
|
vlc_tls_Delete( p_tls );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* delete a host */
|
2004-03-09 21:46:43 +01:00
|
|
|
|
void httpd_HostDelete( httpd_host_t *host )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
int i;
|
2009-07-02 18:06:26 +02:00
|
|
|
|
bool delete = false;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2011-09-25 17:54:42 +02:00
|
|
|
|
vlc_mutex_lock( &httpd.mutex );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_mutex_lock( &host->lock );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
host->i_ref--;
|
2009-01-14 21:07:31 +01:00
|
|
|
|
if( host->i_ref == 0 )
|
2009-07-02 18:06:26 +02:00
|
|
|
|
delete = true;
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_mutex_unlock( &host->lock );
|
2009-07-02 18:06:26 +02:00
|
|
|
|
if( !delete )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
/* still used */
|
2011-09-25 17:54:42 +02:00
|
|
|
|
vlc_mutex_unlock( &httpd.mutex );
|
2009-03-31 21:26:20 +02:00
|
|
|
|
msg_Dbg( host, "httpd_HostDelete: host still in use" );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2011-10-24 03:33:11 +02:00
|
|
|
|
TAB_REMOVE( httpd.i_host, httpd.host, host );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2012-05-09 17:16:58 +02:00
|
|
|
|
vlc_cancel( host->thread );
|
2009-01-17 17:42:38 +01:00
|
|
|
|
vlc_join( host->thread, NULL );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2006-01-22 17:35:59 +01:00
|
|
|
|
msg_Dbg( host, "HTTP host removed" );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
for( i = 0; i < host->i_url; i++ )
|
|
|
|
|
{
|
2006-04-01 13:27:40 +02:00
|
|
|
|
msg_Err( host, "url still registered: %s", host->url[i]->psz_url );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
for( i = 0; i < host->i_client; i++ )
|
|
|
|
|
{
|
|
|
|
|
httpd_client_t *cl = host->client[i];
|
|
|
|
|
msg_Warn( host, "client still connected" );
|
2004-03-09 21:46:43 +01:00
|
|
|
|
httpd_ClientClean( cl );
|
|
|
|
|
TAB_REMOVE( host->i_client, host->client, cl );
|
|
|
|
|
free( cl );
|
|
|
|
|
i--;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
/* TODO */
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-29 22:00:21 +02:00
|
|
|
|
vlc_tls_Delete( host->p_tls );
|
2007-02-21 18:58:12 +01:00
|
|
|
|
net_ListenClose( host->fds );
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_cond_destroy( &host->wait );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
vlc_mutex_destroy( &host->lock );
|
2008-02-26 01:29:12 +01:00
|
|
|
|
vlc_object_release( host );
|
2011-09-25 17:54:42 +02:00
|
|
|
|
vlc_mutex_unlock( &httpd.mutex );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* register a new url */
|
2012-04-01 22:03:23 +02:00
|
|
|
|
httpd_url_t *httpd_UrlNew( httpd_host_t *host, const char *psz_url,
|
|
|
|
|
const char *psz_user, const char *psz_password )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_url_t *url;
|
|
|
|
|
|
2007-09-17 18:56:12 +02:00
|
|
|
|
assert( psz_url != NULL );
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
vlc_mutex_lock( &host->lock );
|
2012-04-01 21:06:13 +02:00
|
|
|
|
for( int i = 0; i < host->i_url; i++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2012-04-01 21:06:13 +02:00
|
|
|
|
if( !strcmp( psz_url, host->url[i]->psz_url ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2012-04-01 21:06:13 +02:00
|
|
|
|
msg_Warn( host,
|
|
|
|
|
"cannot add '%s' (url already defined)", psz_url );
|
|
|
|
|
vlc_mutex_unlock( &host->lock );
|
|
|
|
|
return NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-06 09:53:24 +01:00
|
|
|
|
url = xmalloc( sizeof( httpd_url_t ) );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
url->host = host;
|
|
|
|
|
|
2008-05-04 13:10:08 +02:00
|
|
|
|
vlc_mutex_init( &url->lock );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
url->psz_url = strdup( psz_url );
|
|
|
|
|
url->psz_user = strdup( psz_user ? psz_user : "" );
|
|
|
|
|
url->psz_password = strdup( psz_password ? psz_password : "" );
|
2012-04-01 21:06:13 +02:00
|
|
|
|
for( int i = 0; i < HTTPD_MSG_MAX; i++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
url->catch[i].cb = NULL;
|
|
|
|
|
url->catch[i].p_sys = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TAB_APPEND( host->i_url, host->url, url );
|
2009-01-14 21:07:31 +01:00
|
|
|
|
vlc_cond_signal( &host->wait );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
vlc_mutex_unlock( &host->lock );
|
|
|
|
|
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* register callback on a url */
|
2004-03-09 21:46:43 +01:00
|
|
|
|
int httpd_UrlCatch( httpd_url_t *url, int i_msg, httpd_callback_t cb,
|
|
|
|
|
httpd_callback_sys_t *p_sys )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
vlc_mutex_lock( &url->lock );
|
|
|
|
|
url->catch[i_msg].cb = cb;
|
|
|
|
|
url->catch[i_msg].p_sys= p_sys;
|
|
|
|
|
vlc_mutex_unlock( &url->lock );
|
|
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-03 21:53:49 +02:00
|
|
|
|
/* delete a url */
|
2004-03-09 21:46:43 +01:00
|
|
|
|
void httpd_UrlDelete( httpd_url_t *url )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_host_t *host = url->host;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
vlc_mutex_lock( &host->lock );
|
|
|
|
|
TAB_REMOVE( host->i_url, host->url, url );
|
|
|
|
|
|
|
|
|
|
vlc_mutex_destroy( &url->lock );
|
|
|
|
|
free( url->psz_url );
|
|
|
|
|
free( url->psz_user );
|
|
|
|
|
free( url->psz_password );
|
|
|
|
|
|
|
|
|
|
for( i = 0; i < host->i_client; i++ )
|
|
|
|
|
{
|
|
|
|
|
httpd_client_t *client = host->client[i];
|
|
|
|
|
|
|
|
|
|
if( client->url == url )
|
|
|
|
|
{
|
|
|
|
|
/* TODO complete it */
|
|
|
|
|
msg_Warn( host, "force closing connections" );
|
2004-03-09 21:46:43 +01:00
|
|
|
|
httpd_ClientClean( client );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
TAB_REMOVE( host->i_client, host->client, client );
|
2004-03-09 21:46:43 +01:00
|
|
|
|
free( client );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-03-09 21:46:43 +01:00
|
|
|
|
free( url );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
vlc_mutex_unlock( &host->lock );
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-22 19:04:19 +02:00
|
|
|
|
static void httpd_MsgInit( httpd_message_t *msg )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
msg->cl = NULL;
|
|
|
|
|
msg->i_type = HTTPD_MSG_NONE;
|
|
|
|
|
msg->i_proto = HTTPD_PROTO_NONE;
|
2007-09-02 10:51:01 +02:00
|
|
|
|
msg->i_version = -1; /* FIXME */
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
msg->i_status = 0;
|
|
|
|
|
|
2006-02-10 15:43:05 +01:00
|
|
|
|
msg->psz_url = NULL;
|
|
|
|
|
msg->psz_args = NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2014-02-15 23:15:49 +01:00
|
|
|
|
msg->i_headers = 0;
|
|
|
|
|
msg->p_headers = NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
msg->i_body_offset = 0;
|
|
|
|
|
msg->i_body = 0;
|
2007-08-21 21:16:09 +02:00
|
|
|
|
msg->p_body = NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-10-22 19:04:19 +02:00
|
|
|
|
static void httpd_MsgClean( httpd_message_t *msg )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2008-03-12 00:30:25 +01:00
|
|
|
|
free( msg->psz_url );
|
|
|
|
|
free( msg->psz_args );
|
2014-02-15 23:15:49 +01:00
|
|
|
|
for( size_t i = 0; i < msg->i_headers; i++ )
|
|
|
|
|
{
|
|
|
|
|
free( msg->p_headers[i].name );
|
|
|
|
|
free( msg->p_headers[i].value );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2014-02-15 23:15:49 +01:00
|
|
|
|
free( msg->p_headers );
|
2008-03-12 00:30:25 +01:00
|
|
|
|
free( msg->p_body );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_MsgInit( msg );
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-30 23:29:51 +02:00
|
|
|
|
const char *httpd_MsgGet( const httpd_message_t *msg, const char *name )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-15 23:15:49 +01:00
|
|
|
|
for( size_t i = 0; i < msg->i_headers; i++ )
|
|
|
|
|
{
|
|
|
|
|
if( !strcasecmp( msg->p_headers[i].name, name ))
|
|
|
|
|
{
|
|
|
|
|
return msg->p_headers[i].value;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-03-22 22:01:09 +01:00
|
|
|
|
return NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2006-02-04 20:48:38 +01:00
|
|
|
|
|
2006-11-24 16:16:18 +01:00
|
|
|
|
void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value, ... )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
char *value = NULL;
|
|
|
|
|
|
|
|
|
|
va_start( args, psz_value );
|
2011-01-12 19:37:51 +01:00
|
|
|
|
if( us_vasprintf( &value, psz_value, args ) == -1 )
|
2007-08-20 20:45:41 +02:00
|
|
|
|
value = NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
va_end( args );
|
|
|
|
|
|
2007-08-20 20:45:41 +02:00
|
|
|
|
if( value == NULL )
|
|
|
|
|
return;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
name = strdup( name );
|
2007-08-20 20:45:41 +02:00
|
|
|
|
if( name == NULL )
|
|
|
|
|
{
|
|
|
|
|
free( value );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-02-15 23:15:49 +01:00
|
|
|
|
httpd_header * p_tmp = realloc( msg->p_headers, sizeof(httpd_header) * (msg->i_headers + 1));
|
|
|
|
|
if(p_tmp)
|
|
|
|
|
{
|
|
|
|
|
msg->p_headers = p_tmp;
|
|
|
|
|
msg->p_headers[msg->i_headers].name = name;
|
|
|
|
|
msg->p_headers[msg->i_headers].value = value;
|
|
|
|
|
msg->i_headers++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
free(name);
|
|
|
|
|
free(value);
|
|
|
|
|
}
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-02-21 19:03:40 +01:00
|
|
|
|
static void httpd_ClientInit( httpd_client_t *cl, mtime_t now )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_RECEIVING;
|
2007-02-21 19:03:40 +01:00
|
|
|
|
cl->i_activity_date = now;
|
2008-05-01 21:11:47 +02:00
|
|
|
|
cl->i_activity_timeout = INT64_C(10000000);
|
2005-10-22 18:23:01 +02:00
|
|
|
|
cl->i_buffer_size = HTTPD_CL_BUFSIZE;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->i_buffer = 0;
|
2009-12-06 09:53:24 +01:00
|
|
|
|
cl->p_buffer = xmalloc( cl->i_buffer_size );
|
2013-08-16 16:42:40 +02:00
|
|
|
|
cl->i_keyframe_wait_to_pass = -1;
|
2011-11-03 18:41:56 +01:00
|
|
|
|
cl->b_stream_mode = false;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
httpd_MsgInit( &cl->query );
|
|
|
|
|
httpd_MsgInit( &cl->answer );
|
|
|
|
|
}
|
2004-03-09 21:46:43 +01:00
|
|
|
|
|
2011-08-02 18:00:46 +02:00
|
|
|
|
char* httpd_ClientIP( const httpd_client_t *cl, char *ip, int *port )
|
2004-03-22 13:33:29 +01:00
|
|
|
|
{
|
2011-08-02 18:00:46 +02:00
|
|
|
|
return net_GetPeerAddress( cl->fd, ip, port ) ? NULL : ip;
|
2005-07-29 19:53:50 +02:00
|
|
|
|
}
|
2005-06-26 12:24:35 +02:00
|
|
|
|
|
2011-08-02 18:00:46 +02:00
|
|
|
|
char* httpd_ServerIP( const httpd_client_t *cl, char *ip, int *port )
|
2005-07-29 19:53:50 +02:00
|
|
|
|
{
|
2011-08-02 18:00:46 +02:00
|
|
|
|
return net_GetSockAddress( cl->fd, ip, port ) ? NULL : ip;
|
2004-03-22 13:33:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
static void httpd_ClientClean( httpd_client_t *cl )
|
|
|
|
|
{
|
2004-11-04 23:55:54 +01:00
|
|
|
|
if( cl->fd >= 0 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2004-11-04 23:55:54 +01:00
|
|
|
|
if( cl->p_tls != NULL )
|
2012-09-29 22:00:21 +02:00
|
|
|
|
vlc_tls_SessionDelete( cl->p_tls );
|
2004-07-17 14:30:59 +02:00
|
|
|
|
net_Close( cl->fd );
|
2004-03-10 18:23:16 +01:00
|
|
|
|
cl->fd = -1;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
httpd_MsgClean( &cl->answer );
|
|
|
|
|
httpd_MsgClean( &cl->query );
|
|
|
|
|
|
2008-03-12 00:30:25 +01:00
|
|
|
|
free( cl->p_buffer );
|
|
|
|
|
cl->p_buffer = NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-07-23 13:28:28 +02:00
|
|
|
|
static httpd_client_t *httpd_ClientNew( int fd, vlc_tls_t *p_tls, mtime_t now )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_client_t *cl = malloc( sizeof( httpd_client_t ) );
|
2006-02-10 15:43:05 +01:00
|
|
|
|
|
|
|
|
|
if( !cl ) return NULL;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->i_ref = 0;
|
|
|
|
|
cl->fd = fd;
|
|
|
|
|
cl->url = NULL;
|
2004-11-04 23:55:54 +01:00
|
|
|
|
cl->p_tls = p_tls;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2007-02-21 19:03:40 +01:00
|
|
|
|
httpd_ClientInit( cl, now );
|
2012-09-29 22:00:21 +02:00
|
|
|
|
if( p_tls != NULL )
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_TLS_HS_OUT;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
return cl;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-12 18:52:12 +02:00
|
|
|
|
static
|
|
|
|
|
ssize_t httpd_NetRecv (httpd_client_t *cl, uint8_t *p, size_t i_len)
|
2004-11-04 23:55:54 +01:00
|
|
|
|
{
|
2011-07-23 13:28:28 +02:00
|
|
|
|
vlc_tls_t *p_tls;
|
2008-06-12 18:52:12 +02:00
|
|
|
|
ssize_t val;
|
2006-02-04 20:48:38 +01:00
|
|
|
|
|
2004-11-04 23:55:54 +01:00
|
|
|
|
p_tls = cl->p_tls;
|
2008-06-12 18:52:12 +02:00
|
|
|
|
do
|
|
|
|
|
val = p_tls ? tls_Recv (p_tls, p, i_len)
|
|
|
|
|
: recv (cl->fd, p, i_len, 0);
|
|
|
|
|
while (val == -1 && errno == EINTR);
|
|
|
|
|
return val;
|
2004-11-04 23:55:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-06-12 18:52:12 +02:00
|
|
|
|
static
|
|
|
|
|
ssize_t httpd_NetSend (httpd_client_t *cl, const uint8_t *p, size_t i_len)
|
2004-11-04 23:55:54 +01:00
|
|
|
|
{
|
2011-07-23 13:28:28 +02:00
|
|
|
|
vlc_tls_t *p_tls;
|
2008-06-12 18:52:12 +02:00
|
|
|
|
ssize_t val;
|
2004-11-04 23:55:54 +01:00
|
|
|
|
|
|
|
|
|
p_tls = cl->p_tls;
|
2008-06-12 18:52:12 +02:00
|
|
|
|
do
|
|
|
|
|
val = p_tls ? tls_Send( p_tls, p, i_len )
|
|
|
|
|
: send (cl->fd, p, i_len, 0);
|
|
|
|
|
while (val == -1 && errno == EINTR);
|
|
|
|
|
return val;
|
2004-11-04 23:55:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-09-15 15:43:38 +02:00
|
|
|
|
|
|
|
|
|
static const struct
|
|
|
|
|
{
|
|
|
|
|
const char name[16];
|
|
|
|
|
int i_type;
|
|
|
|
|
int i_proto;
|
|
|
|
|
}
|
|
|
|
|
msg_type[] =
|
|
|
|
|
{
|
|
|
|
|
{ "OPTIONS", HTTPD_MSG_OPTIONS, HTTPD_PROTO_RTSP },
|
|
|
|
|
{ "DESCRIBE", HTTPD_MSG_DESCRIBE, HTTPD_PROTO_RTSP },
|
|
|
|
|
{ "SETUP", HTTPD_MSG_SETUP, HTTPD_PROTO_RTSP },
|
|
|
|
|
{ "PLAY", HTTPD_MSG_PLAY, HTTPD_PROTO_RTSP },
|
|
|
|
|
{ "PAUSE", HTTPD_MSG_PAUSE, HTTPD_PROTO_RTSP },
|
|
|
|
|
{ "GET_PARAMETER", HTTPD_MSG_GETPARAMETER, HTTPD_PROTO_RTSP },
|
|
|
|
|
{ "TEARDOWN", HTTPD_MSG_TEARDOWN, HTTPD_PROTO_RTSP },
|
|
|
|
|
{ "GET", HTTPD_MSG_GET, HTTPD_PROTO_HTTP },
|
|
|
|
|
{ "HEAD", HTTPD_MSG_HEAD, HTTPD_PROTO_HTTP },
|
|
|
|
|
{ "POST", HTTPD_MSG_POST, HTTPD_PROTO_HTTP },
|
|
|
|
|
{ "", HTTPD_MSG_NONE, HTTPD_PROTO_NONE }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
static void httpd_ClientRecv( httpd_client_t *cl )
|
|
|
|
|
{
|
|
|
|
|
int i_len;
|
|
|
|
|
|
2007-09-24 18:22:33 +02:00
|
|
|
|
/* ignore leading whites */
|
|
|
|
|
if( ( cl->query.i_proto == HTTPD_PROTO_NONE ) &&
|
|
|
|
|
( cl->i_buffer == 0 ) )
|
|
|
|
|
{
|
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
|
|
i_len = httpd_NetRecv( cl, &c, 1 );
|
|
|
|
|
|
|
|
|
|
if( ( i_len > 0 ) && ( strchr( "\r\n\t ", c ) == NULL ) )
|
|
|
|
|
{
|
|
|
|
|
cl->p_buffer[0] = c;
|
|
|
|
|
cl->i_buffer++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( cl->query.i_proto == HTTPD_PROTO_NONE )
|
|
|
|
|
{
|
2007-09-15 15:43:38 +02:00
|
|
|
|
/* enough to see if it's Interleaved RTP over RTSP or RTSP/HTTP */
|
2004-11-04 23:55:54 +01:00
|
|
|
|
i_len = httpd_NetRecv( cl, &cl->p_buffer[cl->i_buffer],
|
2007-09-24 18:24:02 +02:00
|
|
|
|
7 - cl->i_buffer );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( i_len > 0 )
|
|
|
|
|
{
|
|
|
|
|
cl->i_buffer += i_len;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-24 19:07:42 +02:00
|
|
|
|
/* The smallest legal request is 7 bytes ("GET /\r\n"),
|
|
|
|
|
* this is the maximum we can ask at this point. */
|
2007-09-24 18:24:02 +02:00
|
|
|
|
if( cl->i_buffer >= 7 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2007-09-24 19:07:42 +02:00
|
|
|
|
if( !memcmp( cl->p_buffer, "HTTP/1.", 7 ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_HTTP;
|
|
|
|
|
cl->query.i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
}
|
2007-09-24 18:24:02 +02:00
|
|
|
|
else if( !memcmp( cl->p_buffer, "RTSP/1.", 7 ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_RTSP;
|
|
|
|
|
cl->query.i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-09-24 19:07:42 +02:00
|
|
|
|
/* We need the full request line to determine the protocol. */
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_HTTP0;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->query.i_type = HTTPD_MSG_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( cl->query.i_body > 0 )
|
|
|
|
|
{
|
|
|
|
|
/* we are reading the body of a request or a channel */
|
2004-11-04 23:55:54 +01:00
|
|
|
|
i_len = httpd_NetRecv( cl, &cl->query.p_body[cl->i_buffer],
|
|
|
|
|
cl->query.i_body - cl->i_buffer );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( i_len > 0 )
|
|
|
|
|
{
|
|
|
|
|
cl->i_buffer += i_len;
|
|
|
|
|
}
|
|
|
|
|
if( cl->i_buffer >= cl->query.i_body )
|
|
|
|
|
{
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* we are reading a header -> char by char */
|
|
|
|
|
for( ;; )
|
|
|
|
|
{
|
2007-09-15 15:43:38 +02:00
|
|
|
|
if( cl->i_buffer == cl->i_buffer_size )
|
|
|
|
|
{
|
2007-09-24 19:07:42 +02:00
|
|
|
|
uint8_t *newbuf = realloc( cl->p_buffer, cl->i_buffer_size + 1024 );
|
2007-09-15 15:43:38 +02:00
|
|
|
|
if( newbuf == NULL )
|
|
|
|
|
{
|
|
|
|
|
i_len = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cl->p_buffer = newbuf;
|
|
|
|
|
cl->i_buffer_size += 1024;
|
|
|
|
|
}
|
|
|
|
|
|
2004-11-04 23:55:54 +01:00
|
|
|
|
i_len = httpd_NetRecv (cl, &cl->p_buffer[cl->i_buffer], 1 );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( i_len <= 0 )
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
cl->i_buffer++;
|
|
|
|
|
|
2007-09-24 19:07:42 +02:00
|
|
|
|
if( ( cl->query.i_proto == HTTPD_PROTO_HTTP0 )
|
|
|
|
|
&& ( cl->p_buffer[cl->i_buffer - 1] == '\n' ) )
|
|
|
|
|
{
|
|
|
|
|
/* Request line is now complete */
|
|
|
|
|
const char *p = memchr( cl->p_buffer, ' ', cl->i_buffer );
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
assert( cl->query.i_type == HTTPD_MSG_NONE );
|
|
|
|
|
|
|
|
|
|
if( p == NULL ) /* no URI: evil guy */
|
|
|
|
|
{
|
|
|
|
|
i_len = 0; /* drop connection */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
p++; /* skips extra spaces */
|
|
|
|
|
while( *p == ' ' );
|
|
|
|
|
|
|
|
|
|
p = memchr( p, ' ', ((char *)cl->p_buffer) + cl->i_buffer - p );
|
|
|
|
|
if( p == NULL ) /* no explicit protocol: HTTP/0.9 */
|
|
|
|
|
{
|
|
|
|
|
i_len = 0; /* not supported currently -> drop */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
p++; /* skips extra spaces ever again */
|
|
|
|
|
while( *p == ' ' );
|
|
|
|
|
|
|
|
|
|
len = ((char *)cl->p_buffer) + cl->i_buffer - p;
|
|
|
|
|
if( len < 7 ) /* foreign protocol */
|
|
|
|
|
i_len = 0; /* I don't understand -> drop */
|
|
|
|
|
else
|
|
|
|
|
if( memcmp( p, "HTTP/1.", 7 ) == 0 )
|
|
|
|
|
{
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_HTTP;
|
|
|
|
|
cl->query.i_version = atoi( p + 7 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if( memcmp( p, "RTSP/1.", 7 ) == 0 )
|
|
|
|
|
{
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_RTSP;
|
|
|
|
|
cl->query.i_version = atoi( p + 7 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if( memcmp( p, "HTTP/", 5 ) == 0 )
|
|
|
|
|
{
|
|
|
|
|
const uint8_t sorry[] =
|
|
|
|
|
"HTTP/1.1 505 Unknown HTTP version\r\n\r\n";
|
|
|
|
|
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
|
|
|
|
|
i_len = 0; /* drop */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if( memcmp( p, "RTSP/", 5 ) == 0 )
|
|
|
|
|
{
|
|
|
|
|
const uint8_t sorry[] =
|
|
|
|
|
"RTSP/1.0 505 Unknown RTSP version\r\n\r\n";
|
|
|
|
|
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
|
|
|
|
|
i_len = 0; /* drop */
|
|
|
|
|
}
|
|
|
|
|
else /* yet another foreign protocol */
|
|
|
|
|
i_len = 0;
|
|
|
|
|
|
|
|
|
|
if( i_len == 0 )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-10 12:03:30 +02:00
|
|
|
|
if( ( cl->i_buffer >= 2 && !memcmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )||
|
|
|
|
|
( cl->i_buffer >= 4 && !memcmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
/* we have finished the header so parse it and set i_body */
|
|
|
|
|
cl->p_buffer[cl->i_buffer] = '\0';
|
|
|
|
|
|
|
|
|
|
if( cl->query.i_type == HTTPD_MSG_ANSWER )
|
|
|
|
|
{
|
2005-07-10 12:03:30 +02:00
|
|
|
|
/* FIXME:
|
|
|
|
|
* assume strlen( "HTTP/1.x" ) = 8
|
|
|
|
|
*/
|
2004-03-09 21:46:43 +01:00
|
|
|
|
cl->query.i_status =
|
2005-07-10 12:03:30 +02:00
|
|
|
|
strtol( (char *)&cl->p_buffer[8],
|
|
|
|
|
&p, 0 );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
while( *p == ' ' )
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-08-21 21:11:34 +02:00
|
|
|
|
unsigned i;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
cl->query.i_type = HTTPD_MSG_NONE;
|
|
|
|
|
|
2005-05-12 23:08:15 +02:00
|
|
|
|
/*fprintf( stderr, "received new request=%s\n", cl->p_buffer);*/
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2007-08-21 21:11:34 +02:00
|
|
|
|
for( i = 0; msg_type[i].name[0]; i++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2005-07-10 12:03:30 +02:00
|
|
|
|
if( !strncmp( (char *)cl->p_buffer, msg_type[i].name,
|
2004-03-09 21:46:43 +01:00
|
|
|
|
strlen( msg_type[i].name ) ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2007-09-02 11:06:57 +02:00
|
|
|
|
p = (char *)&cl->p_buffer[strlen(msg_type[i].name) + 1 ];
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->query.i_type = msg_type[i].i_type;
|
|
|
|
|
if( cl->query.i_proto != msg_type[i].i_proto )
|
|
|
|
|
{
|
|
|
|
|
p = NULL;
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_NONE;
|
|
|
|
|
cl->query.i_type = HTTPD_MSG_NONE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( p == NULL )
|
|
|
|
|
{
|
2005-07-10 12:03:30 +02:00
|
|
|
|
if( strstr( (char *)cl->p_buffer, "HTTP/1." ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_HTTP;
|
|
|
|
|
}
|
2005-07-10 12:03:30 +02:00
|
|
|
|
else if( strstr( (char *)cl->p_buffer, "RTSP/1." ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
cl->query.i_proto = HTTPD_PROTO_RTSP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *p2;
|
|
|
|
|
char *p3;
|
|
|
|
|
|
|
|
|
|
while( *p == ' ' )
|
|
|
|
|
{
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
p2 = strchr( p, ' ' );
|
|
|
|
|
if( p2 )
|
|
|
|
|
{
|
|
|
|
|
*p2++ = '\0';
|
|
|
|
|
}
|
2008-11-27 19:36:43 +01:00
|
|
|
|
if( !strncasecmp( p, ( cl->query.i_proto
|
2011-09-26 17:28:19 +02:00
|
|
|
|
== HTTPD_PROTO_HTTP ) ? "http:" : "rtsp:", 5 ) )
|
2008-11-27 19:36:43 +01:00
|
|
|
|
{ /* Skip hier-part of URL (if present) */
|
2011-09-26 17:28:19 +02:00
|
|
|
|
p += 5;
|
2008-11-27 19:36:43 +01:00
|
|
|
|
if( !strncmp( p, "//", 2 ) ) /* skip authority */
|
|
|
|
|
{ /* see RFC3986 §3.2 */
|
|
|
|
|
p += 2;
|
2011-09-26 17:28:19 +02:00
|
|
|
|
p += strcspn( p, "/?#" );
|
2008-11-27 19:36:43 +01:00
|
|
|
|
}
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2011-09-26 17:28:19 +02:00
|
|
|
|
else
|
|
|
|
|
if( !strncasecmp( p, ( cl->query.i_proto
|
|
|
|
|
== HTTPD_PROTO_HTTP ) ? "https:" : "rtsps:", 6 ) )
|
|
|
|
|
{ /* Skip hier-part of URL (if present) */
|
|
|
|
|
p += 6;
|
|
|
|
|
if( !strncmp( p, "//", 2 ) ) /* skip authority */
|
|
|
|
|
{ /* see RFC3986 §3.2 */
|
|
|
|
|
p += 2;
|
|
|
|
|
p += strcspn( p, "/?#" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->query.psz_url = strdup( p );
|
|
|
|
|
if( ( p3 = strchr( cl->query.psz_url, '?' ) ) )
|
|
|
|
|
{
|
|
|
|
|
*p3++ = '\0';
|
2005-07-10 12:03:30 +02:00
|
|
|
|
cl->query.psz_args = (uint8_t *)strdup( p3 );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
p = p2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( p )
|
|
|
|
|
{
|
|
|
|
|
p = strchr( p, '\n' );
|
|
|
|
|
}
|
|
|
|
|
if( p )
|
|
|
|
|
{
|
|
|
|
|
while( *p == '\n' || *p == '\r' )
|
|
|
|
|
{
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
while( p && *p != '\0' )
|
|
|
|
|
{
|
|
|
|
|
char *line = p;
|
|
|
|
|
char *eol = p = strchr( p, '\n' );
|
|
|
|
|
char *colon;
|
|
|
|
|
|
|
|
|
|
while( eol && eol >= line && ( *eol == '\n' || *eol == '\r' ) )
|
|
|
|
|
{
|
|
|
|
|
*eol-- = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( ( colon = strchr( line, ':' ) ) )
|
|
|
|
|
{
|
|
|
|
|
*colon++ = '\0';
|
|
|
|
|
while( *colon == ' ' )
|
|
|
|
|
{
|
|
|
|
|
colon++;
|
|
|
|
|
}
|
2014-02-15 23:15:49 +01:00
|
|
|
|
httpd_MsgAdd( &cl->query, line, colon );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2014-02-15 23:15:49 +01:00
|
|
|
|
if( !strcasecmp( line, "Content-Length" ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-15 23:15:49 +01:00
|
|
|
|
cl->query.i_body = atol( colon );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( p )
|
|
|
|
|
{
|
|
|
|
|
p++;
|
|
|
|
|
while( *p == '\n' || *p == '\r' )
|
|
|
|
|
{
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( cl->query.i_body > 0 )
|
|
|
|
|
{
|
2010-12-11 00:13:48 +01:00
|
|
|
|
/* TODO Mhh, handle the case where the client only
|
|
|
|
|
* sends a request and closes the connection to
|
|
|
|
|
* mark the end of the body (probably only RTSP) */
|
2010-12-11 00:58:18 +01:00
|
|
|
|
cl->query.p_body = malloc( cl->query.i_body );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->i_buffer = 0;
|
2014-02-16 11:02:02 +01:00
|
|
|
|
if ( cl->query.p_body == NULL ) {
|
|
|
|
|
switch (cl->query.i_proto) {
|
|
|
|
|
case HTTPD_PROTO_HTTP: {
|
|
|
|
|
const uint8_t sorry[] =
|
|
|
|
|
"HTTP/1.1 413 Request Entity Too Large\r\n\r\n";
|
|
|
|
|
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case HTTPD_PROTO_RTSP: {
|
|
|
|
|
const uint8_t sorry[] =
|
|
|
|
|
"RTSP/1.0 413 Request Entity Too Large\r\n\r\n";
|
|
|
|
|
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
assert( 0 );
|
2010-12-11 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
i_len = 0; /* drop */
|
|
|
|
|
}
|
2010-12-11 00:41:08 +01:00
|
|
|
|
break;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* check if the client is to be set to dead */
|
2013-06-05 15:41:18 +02:00
|
|
|
|
#if defined( _WIN32 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
|
|
|
|
|
#else
|
2008-06-12 18:52:12 +02:00
|
|
|
|
if( ( i_len < 0 && errno != EAGAIN ) || ( i_len == 0 ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
if( cl->query.i_proto != HTTPD_PROTO_NONE && cl->query.i_type != HTTPD_MSG_NONE )
|
|
|
|
|
{
|
|
|
|
|
/* connection closed -> end of data */
|
|
|
|
|
if( cl->query.i_body > 0 )
|
|
|
|
|
{
|
|
|
|
|
cl->query.i_body = cl->i_buffer;
|
|
|
|
|
}
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_DEAD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-11-02 16:23:18 +01:00
|
|
|
|
/* XXX: for QT I have to disable timeout. Try to find why */
|
|
|
|
|
if( cl->query.i_proto == HTTPD_PROTO_RTSP )
|
|
|
|
|
cl->i_activity_timeout = 0;
|
|
|
|
|
|
2006-02-10 15:43:05 +01:00
|
|
|
|
#if 0 /* Debugging only */
|
|
|
|
|
if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
fprintf( stderr, "received new request\n" );
|
2004-03-09 21:46:43 +01:00
|
|
|
|
fprintf( stderr, " - proto=%s\n",
|
|
|
|
|
cl->query.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP" );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
fprintf( stderr, " - version=%d\n", cl->query.i_version );
|
|
|
|
|
fprintf( stderr, " - msg=%d\n", cl->query.i_type );
|
|
|
|
|
if( cl->query.i_type == HTTPD_MSG_ANSWER )
|
|
|
|
|
{
|
2004-03-09 21:46:43 +01:00
|
|
|
|
fprintf( stderr, " - answer=%d '%s'\n", cl->query.i_status,
|
|
|
|
|
cl->query.psz_status );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
else if( cl->query.i_type != HTTPD_MSG_NONE )
|
|
|
|
|
{
|
|
|
|
|
fprintf( stderr, " - url=%s\n", cl->query.psz_url );
|
|
|
|
|
}
|
|
|
|
|
for( i = 0; i < cl->query.i_name; i++ )
|
|
|
|
|
{
|
2004-03-09 21:46:43 +01:00
|
|
|
|
fprintf( stderr, " - option name='%s' value='%s'\n",
|
|
|
|
|
cl->query.name[i], cl->query.value[i] );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2006-02-10 15:43:05 +01:00
|
|
|
|
}
|
|
|
|
|
#endif
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void httpd_ClientSend( httpd_client_t *cl )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int i_len;
|
|
|
|
|
|
|
|
|
|
if( cl->i_buffer < 0 )
|
|
|
|
|
{
|
|
|
|
|
/* We need to create the header */
|
|
|
|
|
int i_size = 0;
|
|
|
|
|
char *p;
|
2007-08-21 21:11:34 +02:00
|
|
|
|
const char *psz_status = httpd_ReasonFromCode( cl->answer.i_status );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2007-08-21 21:11:34 +02:00
|
|
|
|
i_size = strlen( "HTTP/1.") + 10 + 10 + strlen( psz_status ) + 5;
|
2014-02-15 23:15:49 +01:00
|
|
|
|
for( i = 0; i < cl->answer.i_headers; i++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-15 23:15:49 +01:00
|
|
|
|
i_size += strlen( cl->answer.p_headers[i].name ) + 2 +
|
|
|
|
|
strlen( cl->answer.p_headers[i].value ) + 2;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( cl->i_buffer_size < i_size )
|
|
|
|
|
{
|
|
|
|
|
cl->i_buffer_size = i_size;
|
|
|
|
|
free( cl->p_buffer );
|
2009-12-06 09:53:24 +01:00
|
|
|
|
cl->p_buffer = xmalloc( i_size );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2005-07-10 12:03:30 +02:00
|
|
|
|
p = (char *)cl->p_buffer;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2007-09-02 10:51:01 +02:00
|
|
|
|
p += sprintf( p, "%s.%u %d %s\r\n",
|
|
|
|
|
cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP/1" : "RTSP/1",
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->answer.i_version,
|
2007-08-21 21:11:34 +02:00
|
|
|
|
cl->answer.i_status, psz_status );
|
2014-02-15 23:15:49 +01:00
|
|
|
|
for( i = 0; i < cl->answer.i_headers; i++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-15 23:15:49 +01:00
|
|
|
|
p += sprintf( p, "%s: %s\r\n", cl->answer.p_headers[i].name,
|
|
|
|
|
cl->answer.p_headers[i].value );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
p += sprintf( p, "\r\n" );
|
|
|
|
|
|
|
|
|
|
cl->i_buffer = 0;
|
|
|
|
|
cl->i_buffer_size = (uint8_t*)p - cl->p_buffer;
|
|
|
|
|
|
2005-05-12 23:08:15 +02:00
|
|
|
|
/*fprintf( stderr, "sending answer\n" );
|
|
|
|
|
fprintf( stderr, "%s", cl->p_buffer );*/
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-11-04 23:55:54 +01:00
|
|
|
|
i_len = httpd_NetSend( cl, &cl->p_buffer[cl->i_buffer],
|
|
|
|
|
cl->i_buffer_size - cl->i_buffer );
|
2005-08-26 20:15:21 +02:00
|
|
|
|
if( i_len >= 0 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
cl->i_buffer += i_len;
|
|
|
|
|
|
|
|
|
|
if( cl->i_buffer >= cl->i_buffer_size )
|
|
|
|
|
{
|
2011-11-03 18:41:56 +01:00
|
|
|
|
if( cl->answer.i_body == 0 && cl->answer.i_body_offset > 0 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
/* catch more body data */
|
2004-03-10 18:23:16 +01:00
|
|
|
|
int i_msg = cl->query.i_type;
|
|
|
|
|
int64_t i_offset = cl->answer.i_body_offset;
|
|
|
|
|
|
|
|
|
|
httpd_MsgClean( &cl->answer );
|
|
|
|
|
cl->answer.i_body_offset = i_offset;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
|
|
|
|
|
&cl->answer, &cl->query );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( cl->answer.i_body > 0 )
|
|
|
|
|
{
|
|
|
|
|
/* send the body data */
|
|
|
|
|
free( cl->p_buffer );
|
|
|
|
|
cl->p_buffer = cl->answer.p_body;
|
|
|
|
|
cl->i_buffer_size = cl->answer.i_body;
|
|
|
|
|
cl->i_buffer = 0;
|
|
|
|
|
|
|
|
|
|
cl->answer.i_body = 0;
|
|
|
|
|
cl->answer.p_body = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* send finished */
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_SEND_DONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-06-05 15:41:18 +02:00
|
|
|
|
#if defined( _WIN32 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
|
|
|
|
|
#else
|
2008-06-12 18:52:12 +02:00
|
|
|
|
if( ( i_len < 0 && errno != EAGAIN ) || ( i_len == 0 ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
/* error */
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_DEAD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-29 22:00:21 +02:00
|
|
|
|
static void httpd_ClientTlsHandshake( httpd_client_t *cl )
|
2004-12-25 22:35:09 +01:00
|
|
|
|
{
|
2014-02-16 11:02:02 +01:00
|
|
|
|
switch( vlc_tls_SessionHandshake( cl->p_tls, NULL, NULL ) ) {
|
|
|
|
|
case -1: cl->i_state = HTTPD_CLIENT_DEAD; break;
|
|
|
|
|
case 0: cl->i_state = HTTPD_CLIENT_RECEIVING; break;
|
|
|
|
|
case 1: cl->i_state = HTTPD_CLIENT_TLS_HS_IN; break;
|
|
|
|
|
case 2: cl->i_state = HTTPD_CLIENT_TLS_HS_OUT; break;
|
2004-12-25 22:35:09 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-16 16:23:21 +01:00
|
|
|
|
static bool httpdAuthOk(const char *user, const char *pass, const char *b64)
|
2014-02-16 12:01:20 +01:00
|
|
|
|
{
|
|
|
|
|
if (!*user && !*pass)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (!b64)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (strncasecmp(b64, "BASIC", 5))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
b64 += 5;
|
|
|
|
|
while (*b64 == ' ')
|
|
|
|
|
b64++;
|
|
|
|
|
|
|
|
|
|
char *given_user = vlc_b64_decode(b64);
|
|
|
|
|
if (!given_user)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
char *given_pass = NULL;
|
|
|
|
|
given_pass = strchr (given_user, ':');
|
|
|
|
|
if (!given_pass)
|
|
|
|
|
goto auth_failed;
|
|
|
|
|
|
|
|
|
|
*given_pass++ = '\0';
|
|
|
|
|
|
|
|
|
|
if (strcmp (given_user, user))
|
|
|
|
|
goto auth_failed;
|
|
|
|
|
|
|
|
|
|
if (strcmp (given_pass, pass))
|
|
|
|
|
goto auth_failed;
|
|
|
|
|
|
|
|
|
|
free( given_user );
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
auth_failed:
|
|
|
|
|
free( given_user );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
static void httpdLoop(httpd_host_t *host)
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-16 11:29:30 +01:00
|
|
|
|
struct pollfd ufd[host->nfd + host->i_client];
|
|
|
|
|
unsigned nfd;
|
|
|
|
|
for( nfd = 0; nfd < host->nfd; nfd++ )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-16 11:29:30 +01:00
|
|
|
|
ufd[nfd].fd = host->fds[nfd];
|
|
|
|
|
ufd[nfd].events = POLLIN;
|
|
|
|
|
ufd[nfd].revents = 0;
|
|
|
|
|
}
|
2007-02-21 18:58:12 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
/* add all socket that should be read/write and close dead connection */
|
|
|
|
|
while( host->i_url <= 0 )
|
|
|
|
|
{
|
|
|
|
|
mutex_cleanup_push( &host->lock );
|
|
|
|
|
vlc_cond_wait( &host->wait, &host->lock );
|
|
|
|
|
vlc_cleanup_pop();
|
|
|
|
|
}
|
2009-01-14 21:07:31 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
mtime_t now = mdate();
|
|
|
|
|
bool b_low_delay = false;
|
2007-02-21 18:58:12 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
int canc = vlc_savecancel();
|
|
|
|
|
for(int i_client = 0; i_client < host->i_client; i_client++ )
|
|
|
|
|
{
|
|
|
|
|
int64_t i_offset;
|
|
|
|
|
httpd_client_t *cl = host->client[i_client];
|
|
|
|
|
if( cl->i_ref < 0 || ( cl->i_ref == 0 &&
|
|
|
|
|
( cl->i_state == HTTPD_CLIENT_DEAD ||
|
|
|
|
|
( cl->i_activity_timeout > 0 &&
|
|
|
|
|
cl->i_activity_date+cl->i_activity_timeout < now) ) ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2014-02-16 11:29:30 +01:00
|
|
|
|
httpd_ClientClean( cl );
|
|
|
|
|
TAB_REMOVE( host->i_client, host->client, cl );
|
|
|
|
|
free( cl );
|
|
|
|
|
i_client--;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2007-02-21 18:58:12 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
struct pollfd *pufd = ufd + nfd;
|
|
|
|
|
assert (pufd < ufd + (sizeof (ufd) / sizeof (ufd[0])));
|
2007-02-21 18:58:12 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
pufd->fd = cl->fd;
|
|
|
|
|
pufd->events = pufd->revents = 0;
|
2007-02-21 18:58:12 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
switch (cl->i_state) {
|
2014-02-16 11:02:02 +01:00
|
|
|
|
case HTTPD_CLIENT_RECEIVING:
|
|
|
|
|
case HTTPD_CLIENT_TLS_HS_IN:
|
2007-02-21 18:58:12 +01:00
|
|
|
|
pufd->events = POLLIN;
|
2014-02-16 11:02:02 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case HTTPD_CLIENT_SENDING:
|
|
|
|
|
case HTTPD_CLIENT_TLS_HS_OUT:
|
2007-02-21 18:58:12 +01:00
|
|
|
|
pufd->events = POLLOUT;
|
2014-02-16 11:02:02 +01:00
|
|
|
|
break;
|
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
case HTTPD_CLIENT_RECEIVE_DONE: {
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_message_t *answer = &cl->answer;
|
|
|
|
|
httpd_message_t *query = &cl->query;
|
|
|
|
|
|
|
|
|
|
httpd_MsgInit( answer );
|
|
|
|
|
|
|
|
|
|
/* Handle what we received */
|
2014-02-16 11:02:02 +01:00
|
|
|
|
switch (query->i_type) {
|
2014-02-16 11:29:30 +01:00
|
|
|
|
case HTTPD_MSG_ANSWER:
|
|
|
|
|
cl->url = NULL;
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_DEAD;
|
2014-02-16 11:02:02 +01:00
|
|
|
|
break;
|
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
case HTTPD_MSG_OPTIONS:
|
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
answer->i_proto = query->i_proto;
|
|
|
|
|
answer->i_status = 200;
|
|
|
|
|
answer->i_body = 0;
|
|
|
|
|
answer->p_body = NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
httpd_MsgAdd( answer, "Server", "VLC/%s", VERSION );
|
|
|
|
|
httpd_MsgAdd( answer, "Content-Length", "0" );
|
2014-02-16 11:02:02 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
switch( query->i_proto )
|
|
|
|
|
{
|
2014-02-16 12:02:22 +01:00
|
|
|
|
case HTTPD_PROTO_HTTP:
|
|
|
|
|
answer->i_version = 1;
|
|
|
|
|
httpd_MsgAdd(answer, "Allow", "GET,HEAD,POST,OPTIONS");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case HTTPD_PROTO_RTSP:
|
|
|
|
|
answer->i_version = 0;
|
|
|
|
|
|
|
|
|
|
const char *p = httpd_MsgGet( query, "Cseq" );
|
|
|
|
|
if( p != NULL )
|
|
|
|
|
httpd_MsgAdd( answer, "Cseq", "%s", p );
|
|
|
|
|
p = httpd_MsgGet( query, "Timestamp" );
|
|
|
|
|
if( p != NULL )
|
|
|
|
|
httpd_MsgAdd( answer, "Timestamp", "%s", p );
|
|
|
|
|
|
|
|
|
|
p = httpd_MsgGet( query, "Require" );
|
|
|
|
|
if( p != NULL ) {
|
|
|
|
|
answer->i_status = 551;
|
|
|
|
|
httpd_MsgAdd( query, "Unsupported", "%s", p );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
httpd_MsgAdd( answer, "Public", "DESCRIBE,SETUP,"
|
|
|
|
|
"TEARDOWN,PLAY,PAUSE,GET_PARAMETER" );
|
|
|
|
|
break;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2006-02-10 15:43:05 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
cl->i_buffer = -1; /* Force the creation of the answer in
|
|
|
|
|
* httpd_ClientSend */
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_SENDING;
|
|
|
|
|
break;
|
2006-11-24 16:46:43 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
case HTTPD_MSG_NONE:
|
|
|
|
|
if( query->i_proto == HTTPD_PROTO_NONE ) {
|
|
|
|
|
cl->url = NULL;
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_DEAD;
|
2014-02-16 12:01:20 +01:00
|
|
|
|
} else {
|
2014-02-16 11:29:30 +01:00
|
|
|
|
/* unimplemented */
|
|
|
|
|
answer->i_proto = query->i_proto ;
|
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
answer->i_version= 0;
|
|
|
|
|
answer->i_status = 501;
|
|
|
|
|
|
|
|
|
|
char *p;
|
|
|
|
|
answer->i_body = httpd_HtmlError (&p, 501, NULL);
|
|
|
|
|
answer->p_body = (uint8_t *)p;
|
|
|
|
|
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
|
|
|
|
|
|
|
|
|
|
cl->i_buffer = -1; /* Force the creation of the answer in httpd_ClientSend */
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_SENDING;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2005-08-26 20:15:21 +02:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
default: {
|
2014-02-16 12:02:22 +01:00
|
|
|
|
int i_msg = query->i_type;
|
|
|
|
|
bool b_auth_failed = false;
|
|
|
|
|
|
|
|
|
|
/* Search the url and trigger callbacks */
|
|
|
|
|
for(int i = 0; i < host->i_url; i++ ) {
|
|
|
|
|
httpd_url_t *url = host->url[i];
|
|
|
|
|
|
|
|
|
|
if (strcmp(url->psz_url, query->psz_url))
|
|
|
|
|
continue;
|
|
|
|
|
if (!url->catch[i_msg].cb)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (answer) {
|
|
|
|
|
b_auth_failed = !httpdAuthOk(url->psz_user,
|
|
|
|
|
url->psz_password,
|
|
|
|
|
httpd_MsgGet(query, "Authorization")); /* BASIC id */
|
|
|
|
|
if (b_auth_failed)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (url->catch[i_msg].cb(url->catch[i_msg].p_sys, cl, answer, query))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if( answer->i_proto == HTTPD_PROTO_NONE )
|
|
|
|
|
cl->i_buffer = cl->i_buffer_size; /* Raw answer from a CGI */
|
|
|
|
|
else
|
|
|
|
|
cl->i_buffer = -1;
|
|
|
|
|
|
|
|
|
|
/* only one url can answer */
|
|
|
|
|
answer = NULL;
|
|
|
|
|
if( cl->url == NULL )
|
|
|
|
|
cl->url = url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( answer ) {
|
|
|
|
|
answer->i_proto = query->i_proto;
|
|
|
|
|
answer->i_type = HTTPD_MSG_ANSWER;
|
|
|
|
|
answer->i_version= 0;
|
|
|
|
|
|
|
|
|
|
if( b_auth_failed ) {
|
|
|
|
|
httpd_MsgAdd( answer, "WWW-Authenticate",
|
|
|
|
|
"Basic realm=\"VLC stream\"" );
|
|
|
|
|
answer->i_status = 401;
|
|
|
|
|
} else
|
|
|
|
|
answer->i_status = 404; /* no url registered */
|
|
|
|
|
|
|
|
|
|
char *p;
|
|
|
|
|
answer->i_body = httpd_HtmlError (&p, answer->i_status,
|
|
|
|
|
query->psz_url);
|
|
|
|
|
answer->p_body = (uint8_t *)p;
|
|
|
|
|
|
|
|
|
|
cl->i_buffer = -1; /* Force the creation of the answer in httpd_ClientSend */
|
|
|
|
|
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
|
|
|
|
|
httpd_MsgAdd( answer, "Content-Type", "%s", "text/html" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_SENDING;
|
|
|
|
|
}
|
2014-02-16 11:02:02 +01:00
|
|
|
|
}
|
2014-02-16 11:29:30 +01:00
|
|
|
|
break;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2014-02-16 11:02:02 +01:00
|
|
|
|
|
|
|
|
|
case HTTPD_CLIENT_SEND_DONE:
|
2011-11-03 18:41:56 +01:00
|
|
|
|
if( !cl->b_stream_mode || cl->answer.i_body_offset == 0 )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
2006-11-24 16:16:18 +01:00
|
|
|
|
const char *psz_connection = httpd_MsgGet( &cl->answer, "Connection" );
|
|
|
|
|
const char *psz_query = httpd_MsgGet( &cl->query, "Connection" );
|
2008-04-14 00:08:29 +02:00
|
|
|
|
bool b_connection = false;
|
|
|
|
|
bool b_keepalive = false;
|
|
|
|
|
bool b_query = false;
|
2006-03-22 22:01:09 +01:00
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->url = NULL;
|
2006-03-22 22:01:09 +01:00
|
|
|
|
if( psz_connection )
|
|
|
|
|
{
|
|
|
|
|
b_connection = ( strcasecmp( psz_connection, "Close" ) == 0 );
|
|
|
|
|
b_keepalive = ( strcasecmp( psz_connection, "Keep-Alive" ) == 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( psz_query )
|
|
|
|
|
{
|
|
|
|
|
b_query = ( strcasecmp( psz_query, "Close" ) == 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( ( ( cl->query.i_proto == HTTPD_PROTO_HTTP ) &&
|
2014-02-16 11:29:30 +01:00
|
|
|
|
( ( cl->query.i_version == 0 && b_keepalive ) ||
|
|
|
|
|
( cl->query.i_version == 1 && !b_connection ) ) ) ||
|
|
|
|
|
( ( cl->query.i_proto == HTTPD_PROTO_RTSP ) &&
|
|
|
|
|
!b_query && !b_connection ) )
|
2004-03-03 14:23:47 +01:00
|
|
|
|
{
|
|
|
|
|
httpd_MsgClean( &cl->query );
|
|
|
|
|
httpd_MsgInit( &cl->query );
|
|
|
|
|
|
|
|
|
|
cl->i_buffer = 0;
|
|
|
|
|
cl->i_buffer_size = 1000;
|
|
|
|
|
free( cl->p_buffer );
|
2009-12-06 09:53:24 +01:00
|
|
|
|
cl->p_buffer = xmalloc( cl->i_buffer_size );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->i_state = HTTPD_CLIENT_RECEIVING;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_DEAD;
|
|
|
|
|
}
|
|
|
|
|
httpd_MsgClean( &cl->answer );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-02-16 11:02:02 +01:00
|
|
|
|
i_offset = cl->answer.i_body_offset;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
httpd_MsgClean( &cl->answer );
|
|
|
|
|
|
|
|
|
|
cl->answer.i_body_offset = i_offset;
|
2004-03-10 18:23:16 +01:00
|
|
|
|
free( cl->p_buffer );
|
|
|
|
|
cl->p_buffer = NULL;
|
|
|
|
|
cl->i_buffer = 0;
|
|
|
|
|
cl->i_buffer_size = 0;
|
|
|
|
|
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->i_state = HTTPD_CLIENT_WAITING;
|
|
|
|
|
}
|
2014-02-16 11:02:02 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case HTTPD_CLIENT_WAITING:
|
|
|
|
|
i_offset = cl->answer.i_body_offset;
|
|
|
|
|
int i_msg = cl->query.i_type;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
|
|
|
|
httpd_MsgInit( &cl->answer );
|
|
|
|
|
cl->answer.i_body_offset = i_offset;
|
|
|
|
|
|
2004-03-09 21:46:43 +01:00
|
|
|
|
cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
|
2014-02-16 11:29:30 +01:00
|
|
|
|
&cl->answer, &cl->query );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
if( cl->answer.i_type != HTTPD_MSG_NONE )
|
|
|
|
|
{
|
2007-02-21 18:58:12 +01:00
|
|
|
|
/* we have new data, so re-enter send mode */
|
2004-03-03 14:23:47 +01:00
|
|
|
|
cl->i_buffer = 0;
|
|
|
|
|
cl->p_buffer = cl->answer.p_body;
|
|
|
|
|
cl->i_buffer_size = cl->answer.i_body;
|
|
|
|
|
cl->answer.p_body = NULL;
|
|
|
|
|
cl->answer.i_body = 0;
|
|
|
|
|
cl->i_state = HTTPD_CLIENT_SENDING;
|
|
|
|
|
}
|
2007-10-01 20:04:10 +02:00
|
|
|
|
}
|
2007-10-01 20:11:03 +02:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
if (pufd->events != 0)
|
|
|
|
|
nfd++;
|
|
|
|
|
else
|
|
|
|
|
b_low_delay = true;
|
|
|
|
|
}
|
|
|
|
|
vlc_mutex_unlock( &host->lock );
|
|
|
|
|
vlc_restorecancel( canc );
|
|
|
|
|
|
|
|
|
|
/* we will wait 20ms (not too big) if HTTPD_CLIENT_WAITING */
|
|
|
|
|
int ret = poll( ufd, nfd, b_low_delay ? 20 : -1 );
|
2012-05-09 17:16:58 +02:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
canc = vlc_savecancel();
|
|
|
|
|
vlc_mutex_lock( &host->lock );
|
|
|
|
|
switch( ret ) {
|
2014-02-16 11:02:02 +01:00
|
|
|
|
case -1:
|
|
|
|
|
if (errno != EINTR) {
|
|
|
|
|
/* Kernel on low memory or a bug: pace */
|
|
|
|
|
msg_Err( host, "polling error: %s", vlc_strerror_c(errno) );
|
|
|
|
|
msleep( 100000 );
|
|
|
|
|
}
|
|
|
|
|
case 0:
|
2014-02-16 11:29:30 +01:00
|
|
|
|
vlc_restorecancel( canc );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2004-03-03 14:23:47 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
/* Handle client sockets */
|
|
|
|
|
now = mdate();
|
|
|
|
|
nfd = host->nfd;
|
2012-05-09 17:16:58 +02:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
for( int i_client = 0; i_client < host->i_client; i_client++ )
|
|
|
|
|
{
|
|
|
|
|
httpd_client_t *cl = host->client[i_client];
|
|
|
|
|
const struct pollfd *pufd = &ufd[nfd];
|
2007-02-25 15:33:13 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
assert( pufd < &ufd[sizeof(ufd) / sizeof(ufd[0])] );
|
2007-02-25 15:33:13 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
if( cl->fd != pufd->fd )
|
|
|
|
|
continue; // we were not waiting for this client
|
|
|
|
|
++nfd;
|
|
|
|
|
if( pufd->revents == 0 )
|
|
|
|
|
continue; // no event received
|
2007-02-25 15:33:13 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
cl->i_activity_date = now;
|
2007-02-25 15:33:13 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
switch (cl->i_state) {
|
2014-02-16 11:02:02 +01:00
|
|
|
|
case HTTPD_CLIENT_RECEIVING: httpd_ClientRecv( cl ); break;
|
|
|
|
|
case HTTPD_CLIENT_SENDING: httpd_ClientSend( cl ); break;
|
|
|
|
|
case HTTPD_CLIENT_TLS_HS_IN:
|
|
|
|
|
case HTTPD_CLIENT_TLS_HS_OUT: httpd_ClientTlsHandshake( cl ); break;
|
2007-02-25 15:33:13 +01:00
|
|
|
|
}
|
2014-02-16 11:29:30 +01:00
|
|
|
|
}
|
2007-02-21 19:03:40 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
/* Handle server sockets (accept new connections) */
|
|
|
|
|
for( nfd = 0; nfd < host->nfd; nfd++ )
|
|
|
|
|
{
|
|
|
|
|
httpd_client_t *cl;
|
|
|
|
|
int fd = ufd[nfd].fd;
|
2007-02-25 15:33:13 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
assert (fd == host->fds[nfd]);
|
2006-02-04 20:48:38 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
if( ufd[nfd].revents == 0 )
|
|
|
|
|
continue;
|
2006-04-27 22:18:14 +02:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
/* */
|
|
|
|
|
fd = vlc_accept (fd, NULL, NULL, true);
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
continue;
|
|
|
|
|
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
|
&(int){ 1 }, sizeof(int));
|
2006-02-04 20:48:38 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
vlc_tls_t *p_tls;
|
2011-07-23 10:45:40 +02:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
if( host->p_tls != NULL )
|
|
|
|
|
p_tls = vlc_tls_SessionCreate( host->p_tls, fd, NULL );
|
|
|
|
|
else
|
|
|
|
|
p_tls = NULL;
|
2007-02-21 18:58:12 +01:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
cl = httpd_ClientNew( fd, p_tls, now );
|
2012-09-29 22:00:21 +02:00
|
|
|
|
|
2014-02-16 11:29:30 +01:00
|
|
|
|
TAB_APPEND( host->i_client, host->client, cl );
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2014-02-16 11:29:30 +01:00
|
|
|
|
|
|
|
|
|
vlc_restorecancel(canc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void* httpd_HostThread( void *data )
|
|
|
|
|
{
|
|
|
|
|
httpd_host_t *host = data;
|
|
|
|
|
|
|
|
|
|
vlc_mutex_lock( &host->lock );
|
|
|
|
|
while( host->i_ref > 0 )
|
|
|
|
|
httpdLoop(host);
|
2012-05-09 17:16:58 +02:00
|
|
|
|
vlc_mutex_unlock( &host->lock );
|
2008-08-07 20:34:04 +02:00
|
|
|
|
return NULL;
|
2004-03-03 14:23:47 +01:00
|
|
|
|
}
|
2014-02-15 23:15:49 +01:00
|
|
|
|
|
|
|
|
|
int httpd_StreamSetHTTPHeaders(httpd_stream_t * p_stream, httpd_header * p_headers, size_t i_headers )
|
|
|
|
|
{
|
|
|
|
|
if( !p_stream )
|
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
|
|
vlc_mutex_lock( &p_stream->lock );
|
|
|
|
|
if( p_stream->p_http_headers )
|
|
|
|
|
{
|
|
|
|
|
for( size_t i = 0; i < p_stream->i_http_headers; i++)
|
|
|
|
|
{
|
|
|
|
|
free( p_stream->p_http_headers[i].name );
|
|
|
|
|
free( p_stream->p_http_headers[i].value );
|
|
|
|
|
}
|
|
|
|
|
free( p_stream->p_http_headers );
|
|
|
|
|
p_stream->p_http_headers = NULL;
|
|
|
|
|
p_stream->i_http_headers = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !p_headers || !i_headers )
|
|
|
|
|
{
|
|
|
|
|
vlc_mutex_unlock( &p_stream->lock );
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p_stream->p_http_headers = malloc(sizeof(httpd_header) * i_headers );
|
|
|
|
|
if( !p_stream->p_http_headers )
|
|
|
|
|
{
|
|
|
|
|
vlc_mutex_unlock( &p_stream->lock );
|
|
|
|
|
return VLC_ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t j = 0;
|
|
|
|
|
for( size_t i = 0; i < i_headers; i++ )
|
|
|
|
|
{
|
|
|
|
|
if( unlikely( !p_headers[i].name || !p_headers[i].value ) )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
p_stream->p_http_headers[j].name = strdup( p_headers[i].name );
|
|
|
|
|
p_stream->p_http_headers[j].value = strdup( p_headers[i].value );
|
|
|
|
|
|
|
|
|
|
if( unlikely( !p_stream->p_http_headers[j].name ||
|
|
|
|
|
!p_stream->p_http_headers[j].value ) )
|
|
|
|
|
{
|
|
|
|
|
free( p_stream->p_http_headers[j].name );
|
|
|
|
|
free( p_stream->p_http_headers[j].value );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
p_stream->i_http_headers = j;
|
|
|
|
|
vlc_mutex_unlock( &p_stream->lock );
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
}
|