Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-2-2
Commits
d6f8f329
Commit
d6f8f329
authored
Feb 20, 2014
by
Rafaël Carré
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
httpd: cosmetics
parent
85724e8f
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
750 additions
and
964 deletions
+750
-964
src/network/httpd.c
src/network/httpd.c
+750
-964
No files found.
src/network/httpd.c
View file @
d6f8f329
...
...
@@ -50,21 +50,21 @@
# include <poll.h>
#endif
#if defined(
_WIN32
)
#if defined(
_WIN32
)
# include <winsock2.h>
#else
# include <sys/socket.h>
#endif
#if defined(
_WIN32
)
#if defined(
_WIN32
)
/* We need HUGE buffer otherwise TCP throughput is very limited */
#define HTTPD_CL_BUFSIZE 1000000
#else
#define HTTPD_CL_BUFSIZE 10000
#endif
static
void
httpd_ClientClean
(
httpd_client_t
*
cl
);
static
void
httpd_AppendData
(
httpd_stream_t
*
stream
,
uint8_t
*
p_data
,
int
i_data
);
static
void
httpd_ClientClean
(
httpd_client_t
*
cl
);
static
void
httpd_AppendData
(
httpd_stream_t
*
stream
,
uint8_t
*
p_data
,
int
i_data
);
/* each host run in his own thread */
struct
httpd_host_t
...
...
@@ -177,7 +177,7 @@ struct httpd_client_t
/*****************************************************************************
* Various functions
*****************************************************************************/
static
const
char
*
httpd_ReasonFromCode
(
unsigned
i_code
)
static
const
char
*
httpd_ReasonFromCode
(
unsigned
i_code
)
{
typedef
struct
{
...
...
@@ -248,7 +248,7 @@ static const char *httpd_ReasonFromCode( unsigned i_code )
"Continue"
,
"OK"
,
"Found"
,
"Client error"
,
"Server error"
};
assert
(
(
i_code
>=
100
)
&&
(
i_code
<=
599
)
);
assert
(
(
i_code
>=
100
)
&&
(
i_code
<=
599
)
);
const
http_status_info
*
p
=
http_reason
;
while
(
i_code
<
p
->
i_code
)
...
...
@@ -263,7 +263,7 @@ static const char *httpd_ReasonFromCode( unsigned i_code )
static
size_t
httpd_HtmlError
(
char
**
body
,
int
code
,
const
char
*
url
)
{
const
char
*
errname
=
httpd_ReasonFromCode
(
code
);
assert
(
errname
!=
NULL
);
assert
(
errname
);
char
*
url_Encoded
=
convert_xml_special_chars
(
url
?
url
:
""
);
...
...
@@ -285,8 +285,7 @@ static size_t httpd_HtmlError (char **body, int code, const char *url)
free
(
url_Encoded
);
if
(
res
==
-
1
)
{
if
(
res
==
-
1
)
{
*
body
=
NULL
;
return
0
;
}
...
...
@@ -311,34 +310,29 @@ struct httpd_file_t
};
static
int
httpd_FileCallBack
(
httpd_callback_sys_t
*
p_sys
,
httpd_client_t
*
cl
,
httpd_message_t
*
answer
,
const
httpd_message_t
*
query
)
httpd_FileCallBack
(
httpd_callback_sys_t
*
p_sys
,
httpd_client_t
*
cl
,
httpd_message_t
*
answer
,
const
httpd_message_t
*
query
)
{
httpd_file_t
*
file
=
(
httpd_file_t
*
)
p_sys
;
uint8_t
**
pp_body
,
*
p_body
;
const
char
*
psz_connection
;
uint8_t
**
pp_body
,
*
p_body
;
const
char
*
psz_connection
;
int
*
pi_body
,
i_body
;
if
(
answer
==
NULL
||
query
==
NULL
)
{
if
(
!
answer
||
!
query
)
return
VLC_SUCCESS
;
}
answer
->
i_proto
=
HTTPD_PROTO_HTTP
;
answer
->
i_version
=
1
;
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"
);
httpd_MsgAdd
(
answer
,
"Content-type"
,
"%s"
,
file
->
psz_mime
);
httpd_MsgAdd
(
answer
,
"Cache-Control"
,
"%s"
,
"no-cache"
);
if
(
query
->
i_type
!=
HTTPD_MSG_HEAD
)
{
if
(
query
->
i_type
!=
HTTPD_MSG_HEAD
)
{
pp_body
=
&
answer
->
p_body
;
pi_body
=
&
answer
->
i_body
;
}
else
{
}
else
{
/* The file still needs to be executed. */
p_body
=
NULL
;
i_body
=
0
;
...
...
@@ -346,79 +340,71 @@ httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl,
pi_body
=
&
i_body
;
}
if
(
query
->
i_type
==
HTTPD_MSG_POST
)
{
if
(
query
->
i_type
==
HTTPD_MSG_POST
)
{
/* msg_Warn not supported */
}
uint8_t
*
psz_args
=
query
->
psz_args
;
file
->
pf_fill
(
file
->
p_sys
,
file
,
psz_args
,
pp_body
,
pi_body
);
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
);
}
if
(
query
->
i_type
==
HTTPD_MSG_HEAD
)
free
(
p_body
);
/* We respect client request */
psz_connection
=
httpd_MsgGet
(
&
cl
->
query
,
"Connection"
);
if
(
psz_connection
!=
NULL
)
{
httpd_MsgAdd
(
answer
,
"Connection"
,
"%s"
,
psz_connection
);
}
psz_connection
=
httpd_MsgGet
(
&
cl
->
query
,
"Connection"
);
if
(
!
psz_connection
)
httpd_MsgAdd
(
answer
,
"Connection"
,
"%s"
,
psz_connection
);
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"%d"
,
answer
->
i_body
);
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"%d"
,
answer
->
i_body
);
return
VLC_SUCCESS
;
}
httpd_file_t
*
httpd_FileNew
(
httpd_host_t
*
host
,
httpd_file_t
*
httpd_FileNew
(
httpd_host_t
*
host
,
const
char
*
psz_url
,
const
char
*
psz_mime
,
const
char
*
psz_user
,
const
char
*
psz_password
,
httpd_file_callback_t
pf_fill
,
httpd_file_sys_t
*
p_sys
)
httpd_file_sys_t
*
p_sys
)
{
httpd_file_t
*
file
=
xmalloc
(
sizeof
(
httpd_file_t
)
);
httpd_file_t
*
file
=
malloc
(
sizeof
(
*
file
));
if
(
!
file
)
return
NULL
;
file
->
url
=
httpd_UrlNew
(
host
,
psz_url
,
psz_user
,
psz_password
);
if
(
file
->
url
==
NULL
)
{
free
(
file
);
file
->
url
=
httpd_UrlNew
(
host
,
psz_url
,
psz_user
,
psz_password
);
if
(
!
file
->
url
)
{
free
(
file
);
return
NULL
;
}
file
->
psz_url
=
strdup
(
psz_url
);
if
(
psz_mime
&&
*
psz_mime
)
{
file
->
psz_mime
=
strdup
(
psz_mime
);
}
file
->
psz_url
=
strdup
(
psz_url
);
if
(
psz_mime
&&
*
psz_mime
)
file
->
psz_mime
=
strdup
(
psz_mime
);
else
{
file
->
psz_mime
=
strdup
(
vlc_mime_Ext2Mime
(
psz_url
)
);
}
file
->
psz_mime
=
strdup
(
vlc_mime_Ext2Mime
(
psz_url
));
file
->
pf_fill
=
pf_fill
;
file
->
p_sys
=
p_sys
;
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
);
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
);
return
file
;
}
httpd_file_sys_t
*
httpd_FileDelete
(
httpd_file_t
*
file
)
httpd_file_sys_t
*
httpd_FileDelete
(
httpd_file_t
*
file
)
{
httpd_file_sys_t
*
p_sys
=
file
->
p_sys
;
httpd_UrlDelete
(
file
->
url
);
httpd_UrlDelete
(
file
->
url
);
free
(
file
->
psz_url
);
free
(
file
->
psz_mime
);
free
(
file
->
psz_url
);
free
(
file
->
psz_mime
);
free
(
file
);
free
(
file
);
return
p_sys
;
}
...
...
@@ -436,120 +422,109 @@ struct httpd_handler_t
};
static
int
httpd_HandlerCallBack
(
httpd_callback_sys_t
*
p_sys
,
httpd_client_t
*
cl
,
httpd_message_t
*
answer
,
const
httpd_message_t
*
query
)
httpd_HandlerCallBack
(
httpd_callback_sys_t
*
p_sys
,
httpd_client_t
*
cl
,
httpd_message_t
*
answer
,
const
httpd_message_t
*
query
)
{
httpd_handler_t
*
handler
=
(
httpd_handler_t
*
)
p_sys
;
char
psz_remote_addr
[
NI_MAXNUMERICHOST
];
if
(
answer
==
NULL
||
query
==
NULL
)
{
if
(
!
answer
||
!
query
)
return
VLC_SUCCESS
;
}
answer
->
i_proto
=
HTTPD_PROTO_NONE
;
answer
->
i_type
=
HTTPD_MSG_ANSWER
;
/* We do it ourselves, thanks */
answer
->
i_status
=
0
;
if
(
httpd_ClientIP
(
cl
,
psz_remote_addr
,
NULL
)
==
NULL
)
if
(
!
httpd_ClientIP
(
cl
,
psz_remote_addr
,
NULL
)
)
*
psz_remote_addr
=
'\0'
;
uint8_t
*
psz_args
=
query
->
psz_args
;
handler
->
pf_fill
(
handler
->
p_sys
,
handler
,
query
->
psz_url
,
psz_args
,
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
);
&
answer
->
p_body
,
&
answer
->
i_body
);
if
(
query
->
i_type
==
HTTPD_MSG_HEAD
)
{
if
(
query
->
i_type
==
HTTPD_MSG_HEAD
)
{
char
*
p
=
(
char
*
)
answer
->
p_body
;
/* Looks for end of header (i.e. one empty line) */
while
(
(
p
=
strchr
(
p
,
'\r'
))
!=
NULL
)
{
if
(
p
[
1
]
&&
p
[
1
]
==
'\n'
&&
p
[
2
]
&&
p
[
2
]
==
'\r'
&&
p
[
3
]
&&
p
[
3
]
==
'\n'
)
{
while
((
p
=
strchr
(
p
,
'\r'
)))
if
(
p
[
1
]
==
'\n'
&&
p
[
2
]
==
'\r'
&&
p
[
3
]
==
'\n'
)
break
;
}
}
if
(
p
!=
NULL
)
{
if
(
p
)
{
p
[
4
]
=
'\0'
;
answer
->
i_body
=
strlen
((
char
*
)
answer
->
p_body
)
+
1
;
answer
->
p_body
=
xrealloc
(
answer
->
p_body
,
answer
->
i_body
);
answer
->
p_body
=
xrealloc
(
answer
->
p_body
,
answer
->
i_body
);
}
}
if
(
strncmp
(
(
char
*
)
answer
->
p_body
,
"HTTP/1."
,
7
)
)
{
if
(
strncmp
((
char
*
)
answer
->
p_body
,
"HTTP/1."
,
7
))
{
int
i_status
,
i_headers
;
char
*
psz_headers
,
*
psz_new
;
const
char
*
psz_status
;
if
(
!
strncmp
(
(
char
*
)
answer
->
p_body
,
"Status: "
,
8
)
)
{
if
(
!
strncmp
((
char
*
)
answer
->
p_body
,
"Status: "
,
8
))
{
/* Apache-style */
i_status
=
strtol
(
(
char
*
)
&
answer
->
p_body
[
8
],
&
psz_headers
,
0
);
if
(
*
psz_headers
==
'\r'
||
*
psz_headers
==
'\n'
)
psz_headers
++
;
if
(
*
psz_headers
==
'\n'
)
psz_headers
++
;
i_status
=
strtol
(
(
char
*
)
&
answer
->
p_body
[
8
],
&
psz_headers
,
0
);
if
(
*
psz_headers
==
'\r'
||
*
psz_headers
==
'\n'
)
psz_headers
++
;
if
(
*
psz_headers
==
'\n'
)
psz_headers
++
;
i_headers
=
answer
->
i_body
-
(
psz_headers
-
(
char
*
)
answer
->
p_body
);
}
else
{
}
else
{
i_status
=
200
;
psz_headers
=
(
char
*
)
answer
->
p_body
;
i_headers
=
answer
->
i_body
;
}
psz_status
=
httpd_ReasonFromCode
(
i_status
);
psz_status
=
httpd_ReasonFromCode
(
i_status
);
answer
->
i_body
=
sizeof
(
"HTTP/1.0 xxx
\r\n
"
)
+
strlen
(
psz_status
)
+
i_headers
-
1
;
psz_new
=
(
char
*
)
xmalloc
(
answer
->
i_body
+
1
);
sprintf
(
psz_new
,
"HTTP/1.0 %03d %s
\r\n
"
,
i_status
,
psz_status
);
memcpy
(
&
psz_new
[
strlen
(
psz_new
)],
psz_headers
,
i_headers
);
free
(
answer
->
p_body
);
psz_new
=
(
char
*
)
xmalloc
(
answer
->
i_body
+
1
);
sprintf
(
psz_new
,
"HTTP/1.0 %03d %s
\r\n
"
,
i_status
,
psz_status
);
memcpy
(
&
psz_new
[
strlen
(
psz_new
)],
psz_headers
,
i_headers
);
free
(
answer
->
p_body
);
answer
->
p_body
=
(
uint8_t
*
)
psz_new
;
}
return
VLC_SUCCESS
;
}
httpd_handler_t
*
httpd_HandlerNew
(
httpd_host_t
*
host
,
const
char
*
psz_url
,
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
)
httpd_handler_sys_t
*
p_sys
)
{
httpd_handler_t
*
handler
=
xmalloc
(
sizeof
(
httpd_handler_t
)
);
httpd_handler_t
*
handler
=
malloc
(
sizeof
(
*
handler
));
if
(
!
handler
)
return
NULL
;
handler
->
url
=
httpd_UrlNew
(
host
,
psz_url
,
psz_user
,
psz_password
);
if
(
handler
->
url
==
NULL
)
{
free
(
handler
);
handler
->
url
=
httpd_UrlNew
(
host
,
psz_url
,
psz_user
,
psz_password
);
if
(
!
handler
->
url
)
{
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
);
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
;
}
httpd_handler_sys_t
*
httpd_HandlerDelete
(
httpd_handler_t
*
handler
)
httpd_handler_sys_t
*
httpd_HandlerDelete
(
httpd_handler_t
*
handler
)
{
httpd_handler_sys_t
*
p_sys
=
handler
->
p_sys
;
httpd_UrlDelete
(
handler
->
url
);
free
(
handler
);
httpd_UrlDelete
(
handler
->
url
);
free
(
handler
);
return
p_sys
;
}
...
...
@@ -562,18 +537,17 @@ struct httpd_redirect_t
char
*
psz_dst
;
};
static
int
httpd_RedirectCallBack
(
httpd_callback_sys_t
*
p_sys
,
static
int
httpd_RedirectCallBack
(
httpd_callback_sys_t
*
p_sys
,
httpd_client_t
*
cl
,
httpd_message_t
*
answer
,
const
httpd_message_t
*
query
)
const
httpd_message_t
*
query
)
{
httpd_redirect_t
*
rdir
=
(
httpd_redirect_t
*
)
p_sys
;
char
*
p_body
;
(
void
)
cl
;
if
(
answer
==
NULL
||
query
==
NULL
)
{
if
(
!
answer
||
!
query
)
return
VLC_SUCCESS
;
}
answer
->
i_proto
=
HTTPD_PROTO_HTTP
;
answer
->
i_version
=
1
;
answer
->
i_type
=
HTTPD_MSG_ANSWER
;
...
...
@@ -583,43 +557,44 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys,
answer
->
p_body
=
(
unsigned
char
*
)
p_body
;
/* 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
,
"Location"
,
"%s"
,
rdir
->
psz_dst
);
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"%d"
,
answer
->
i_body
);
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"%d"
,
answer
->
i_body
);
return
VLC_SUCCESS
;
}
httpd_redirect_t
*
httpd_RedirectNew
(
httpd_host_t
*
host
,
const
char
*
psz_url_dst
,
const
char
*
psz_url_src
)
httpd_redirect_t
*
httpd_RedirectNew
(
httpd_host_t
*
host
,
const
char
*
psz_url_dst
,
const
char
*
psz_url_src
)
{
httpd_redirect_t
*
rdir
=
xmalloc
(
sizeof
(
httpd_redirect_t
)
);
httpd_redirect_t
*
rdir
=
malloc
(
sizeof
(
*
rdir
));
if
(
!
rdir
)
return
NULL
;
rdir
->
url
=
httpd_UrlNew
(
host
,
psz_url_src
,
NULL
,
NULL
);
if
(
rdir
->
url
==
NULL
)
{
free
(
rdir
);
rdir
->
url
=
httpd_UrlNew
(
host
,
psz_url_src
,
NULL
,
NULL
);
if
(
!
rdir
->
url
)
{
free
(
rdir
);
return
NULL
;
}
rdir
->
psz_dst
=
strdup
(
psz_url_dst
);
rdir
->
psz_dst
=
strdup
(
psz_url_dst
);
/* 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
);
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
);
return
rdir
;
}
void
httpd_RedirectDelete
(
httpd_redirect_t
*
rdir
)
void
httpd_RedirectDelete
(
httpd_redirect_t
*
rdir
)
{
httpd_UrlDelete
(
rdir
->
url
);
free
(
rdir
->
psz_dst
);
free
(
rdir
);
httpd_UrlDelete
(
rdir
->
url
);
free
(
rdir
->
psz_dst
);
free
(
rdir
);
}
/*****************************************************************************
...
...
@@ -655,29 +630,23 @@ struct httpd_stream_t
httpd_header
*
p_http_headers
;
};
static
int
httpd_StreamCallBack
(
httpd_callback_sys_t
*
p_sys
,
static
int
httpd_StreamCallBack
(
httpd_callback_sys_t
*
p_sys
,
httpd_client_t
*
cl
,
httpd_message_t
*
answer
,
const
httpd_message_t
*
query
)
const
httpd_message_t
*
query
)
{
httpd_stream_t
*
stream
=
(
httpd_stream_t
*
)
p_sys
;
if
(
answer
==
NULL
||
query
==
NULL
||
cl
==
NULL
)
{
if
(
!
answer
||
!
query
||
!
cl
)
return
VLC_SUCCESS
;
}
if
(
answer
->
i_body_offset
>
0
)
{
int64_t
i_write
;
if
(
answer
->
i_body_offset
>
0
)
{
int
i_pos
;
if
(
answer
->
i_body_offset
>=
stream
->
i_buffer_pos
)
{
if
(
answer
->
i_body_offset
>=
stream
->
i_buffer_pos
)
return
VLC_EGENERIC
;
/* wait, no data available */
}
if
(
cl
->
i_keyframe_wait_to_pass
>=
0
)
{
if
(
stream
->
i_last_keyframe_seen_pos
<=
cl
->
i_keyframe_wait_to_pass
)
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
;
...
...
@@ -685,26 +654,20 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
answer
->
i_body_offset
=
stream
->
i_last_keyframe_seen_pos
;
cl
->
i_keyframe_wait_to_pass
=
-
1
;
}
if
(
answer
->
i_body_offset
+
stream
->
i_buffer_size
<
stream
->
i_buffer_pos
)
{
/* this client isn't fast enough */
answer
->
i_body_offset
=
stream
->
i_buffer_last_pos
;
}
if
(
answer
->
i_body_offset
+
stream
->
i_buffer_size
<
stream
->
i_buffer_pos
)
answer
->
i_body_offset
=
stream
->
i_buffer_last_pos
;
/* this client isn't fast enough */
i_pos
=
answer
->
i_body_offset
%
stream
->
i_buffer_size
;
i_write
=
stream
->
i_buffer_pos
-
answer
->
i_body_offset
;
if
(
i_write
>
HTTPD_CL_BUFSIZE
)
{
i
nt64_t
i
_write
=
stream
->
i_buffer_pos
-
answer
->
i_body_offset
;
if
(
i_write
>
HTTPD_CL_BUFSIZE
)
i_write
=
HTTPD_CL_BUFSIZE
;
}
else
if
(
i_write
<=
0
)
{
else
if
(
i_write
<=
0
)
return
VLC_EGENERIC
;
/* wait, no data available */
}
/* Don't go past the end of the circular buffer */
i_write
=
__MIN
(
i_write
,
stream
->
i_buffer_size
-
i_pos
);
i_write
=
__MIN
(
i_write
,
stream
->
i_buffer_size
-
i_pos
);
/* using HTTPD_MSG_ANSWER -> data available */
answer
->
i_proto
=
HTTPD_PROTO_HTTP
;
...
...
@@ -712,15 +675,13 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
answer
->
i_type
=
HTTPD_MSG_ANSWER
;
answer
->
i_body
=
i_write
;
answer
->
p_body
=
xmalloc
(
i_write
);
memcpy
(
answer
->
p_body
,
&
stream
->
p_buffer
[
i_pos
],
i_write
);
answer
->
p_body
=
xmalloc
(
i_write
);
memcpy
(
answer
->
p_body
,
&
stream
->
p_buffer
[
i_pos
],
i_write
);
answer
->
i_body_offset
+=
i_write
;
return
VLC_SUCCESS
;
}
else
{
}
else
{
answer
->
i_proto
=
HTTPD_PROTO_HTTP
;
answer
->
i_version
=
0
;
answer
->
i_type
=
HTTPD_MSG_ANSWER
;
...
...
@@ -730,108 +691,91 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
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
);
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
)
)
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
)
)
else
if
(
!
strncasecmp
(
stream
->
p_http_headers
[
i
].
name
,
"Cache-Control"
,
13
)
)
b_has_cache_control
=
true
;
}
}
vlc_mutex_unlock
(
&
stream
->
lock
);
vlc_mutex_unlock
(
&
stream
->
lock
);
if
(
query
->
i_type
!=
HTTPD_MSG_HEAD
)
{
if
(
query
->
i_type
!=
HTTPD_MSG_HEAD
)
{
cl
->
b_stream_mode
=
true
;
vlc_mutex_lock
(
&
stream
->
lock
);
vlc_mutex_lock
(
&
stream
->
lock
);
/* Send the header */
if
(
stream
->
i_header
>
0
)
{
if
(
stream
->
i_header
>
0
)
{
answer
->
i_body
=
stream
->
i_header
;
answer
->
p_body
=
xmalloc
(
stream
->
i_header
);
memcpy
(
answer
->
p_body
,
stream
->
p_header
,
stream
->
i_header
);
answer
->
p_body
=
xmalloc
(
stream
->
i_header
);
memcpy
(
answer
->
p_body
,
stream
->
p_header
,
stream
->
i_header
);
}
answer
->
i_body_offset
=
stream
->
i_buffer_last_pos
;
if
(
stream
->
b_has_keyframes
)
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
;
vlc_mutex_unlock
(
&
stream
->
lock
);
}
else
{
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"0"
);
vlc_mutex_unlock
(
&
stream
->
lock
);
}
else
{
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"0"
);
answer
->
i_body_offset
=
0
;
}
/* FIXME: move to http access_output */
if
(
!
strcmp
(
stream
->
psz_mime
,
"video/x-ms-asf-stream"
)
)
{
if
(
!
strcmp
(
stream
->
psz_mime
,
"video/x-ms-asf-stream"
))
{
bool
b_xplaystream
=
false
;
httpd_MsgAdd
(
answer
,
"Content-type"
,
"application/octet-stream"
);
httpd_MsgAdd
(
answer
,
"Server"
,
"Cougar 4.1.0.3921"
);
httpd_MsgAdd
(
answer
,
"Pragma"
,
"no-cache"
);
httpd_MsgAdd
(
answer
,
"Pragma"
,
"client-id=%lu"
,
vlc_mrand48
()
&
0x7fff
);
httpd_MsgAdd
(
answer
,
"Pragma"
,
"features=
\"
broadcast
\"
"
);
httpd_MsgAdd
(
answer
,
"Content-type"
,
"application/octet-stream"
);
httpd_MsgAdd
(
answer
,
"Server"
,
"Cougar 4.1.0.3921"
);
httpd_MsgAdd
(
answer
,
"Pragma"
,
"no-cache"
);
httpd_MsgAdd
(
answer
,
"Pragma"
,
"client-id=%lu"
,
vlc_mrand48
()
&
0x7fff
);
httpd_MsgAdd
(
answer
,
"Pragma"
,
"features=
\"
broadcast
\"
"
);
/* Check if there is a xPlayStrm=1 */
for
(
size_t
i
=
0
;
i
<
query
->
i_headers
;
i
++
)
{
if
(
!
strcasecmp
(
query
->
p_headers
[
i
].
name
,
"Pragma"
)
&&
strstr
(
query
->
p_headers
[
i
].
value
,
"xPlayStrm=1"
)
)
{
for
(
size_t
i
=
0
;
i
<
query
->
i_headers
;
i
++
)
if
(
!
strcasecmp
(
query
->
p_headers
[
i
].
name
,
"Pragma"
)
&&
strstr
(
query
->
p_headers
[
i
].
value
,
"xPlayStrm=1"
))
b_xplaystream
=
true
;
}
}
if
(
!
b_xplaystream
)
{
if
(
!
b_xplaystream
)
answer
->
i_body_offset
=
0
;
}
}
else
if
(
!
b_has_content_type
)
{
httpd_MsgAdd
(
answer
,
"Content-type"
,
stream
->
psz_mime
);
}
if
(
!
b_has_cache_control
)
httpd_MsgAdd
(
answer
,
"Cache-Control"
,
"no-cache"
);
}
else
if
(
!
b_has_content_type
)
httpd_MsgAdd
(
answer
,
"Content-type"
,
stream
->
psz_mime
);
if
(
!
b_has_cache_control
)
httpd_MsgAdd
(
answer
,
"Cache-Control"
,
"no-cache"
);
return
VLC_SUCCESS
;
}
}
httpd_stream_t
*
httpd_StreamNew
(
httpd_host_t
*
host
,
httpd_stream_t
*
httpd_StreamNew
(
httpd_host_t
*
host
,
const
char
*
psz_url
,
const
char
*
psz_mime
,
const
char
*
psz_user
,
const
char
*
psz_password
)
const
char
*
psz_user
,
const
char
*
psz_password
)
{
httpd_stream_t
*
stream
=
xmalloc
(
sizeof
(
httpd_stream_t
)
);
httpd_stream_t
*
stream
=
malloc
(
sizeof
(
*
stream
));
if
(
!
stream
)
return
NULL
;
stream
->
url
=
httpd_UrlNew
(
host
,
psz_url
,
psz_user
,
psz_password
);
if
(
stream
->
url
==
NULL
)
{
free
(
stream
);
stream
->
url
=
httpd_UrlNew
(
host
,
psz_url
,
psz_user
,
psz_password
);
if
(
!
stream
->
url
)
{
free
(
stream
);
return
NULL
;
}
vlc_mutex_init
(
&
stream
->
lock
);
if
(
psz_mime
&&
*
psz_mime
)
{
stream
->
psz_mime
=
strdup
(
psz_mime
);
}
vlc_mutex_init
(
&
stream
->
lock
);
if
(
psz_mime
&&
*
psz_mime
)
stream
->
psz_mime
=
strdup
(
psz_mime
);
else
{
stream
->
psz_mime
=
strdup
(
vlc_mime_Ext2Mime
(
psz_url
)
);
}
stream
->
psz_mime
=
strdup
(
vlc_mime_Ext2Mime
(
psz_url
));
stream
->
i_header
=
0
;
stream
->
p_header
=
NULL
;
stream
->
i_buffer_size
=
5000000
;
/* 5 Mo per stream */
stream
->
p_buffer
=
xmalloc
(
stream
->
i_buffer_size
);
stream
->
p_buffer
=
xmalloc
(
stream
->
i_buffer_size
);
/* We set to 1 to make life simpler
* (this way i_body_offset can never be 0) */
stream
->
i_buffer_pos
=
1
;
...
...
@@ -841,47 +785,43 @@ httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
stream
->
i_http_headers
=
0
;
stream
->
p_http_headers
=
NULL
;
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
);
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
);
return
stream
;
}
int
httpd_StreamHeader
(
httpd_stream_t
*
stream
,
uint8_t
*
p_data
,
int
i_data
)
int
httpd_StreamHeader
(
httpd_stream_t
*
stream
,
uint8_t
*
p_data
,
int
i_data
)
{
vlc_mutex_lock
(
&
stream
->
lock
);
free
(
stream
->
p_header
);
vlc_mutex_lock
(
&
stream
->
lock
);
free
(
stream
->
p_header
);
stream
->
p_header
=
NULL
;
stream
->
i_header
=
i_data
;
if
(
i_data
>
0
)
{
stream
->
p_header
=
xmalloc
(
i_data
);
memcpy
(
stream
->
p_header
,
p_data
,
i_data
);
if
(
i_data
>
0
)
{
stream
->
p_header
=
xmalloc
(
i_data
);
memcpy
(
stream
->
p_header
,
p_data
,
i_data
);
}
vlc_mutex_unlock
(
&
stream
->
lock
);
vlc_mutex_unlock
(
&
stream
->
lock
);
return
VLC_SUCCESS
;
}
static
void
httpd_AppendData
(
httpd_stream_t
*
stream
,
uint8_t
*
p_data
,
int
i_data
)
static
void
httpd_AppendData
(
httpd_stream_t
*
stream
,
uint8_t
*
p_data
,
int
i_data
)
{
int
i_pos
=
stream
->
i_buffer_pos
%
stream
->
i_buffer_size
;
int
i_count
=
i_data
;
while
(
i_count
>
0
)
{
int
i_copy
;
i_copy
=
__MIN
(
i_count
,
stream
->
i_buffer_size
-
i_pos
);
while
(
i_count
>
0
)
{
int
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
);
memcpy
(
&
stream
->
p_buffer
[
i_pos
],
p_data
,
i_copy
);
i_pos
=
(
i_pos
+
i_copy
)
%
stream
->
i_buffer_size
;
i_pos
=
(
i_pos
+
i_copy
)
%
stream
->
i_buffer_size
;
i_count
-=
i_copy
;
p_data
+=
i_copy
;
}
...
...
@@ -889,115 +829,106 @@ static void httpd_AppendData( httpd_stream_t *stream, uint8_t *p_data, int i_dat
stream
->
i_buffer_pos
+=
i_data
;
}
int
httpd_StreamSend
(
httpd_stream_t
*
stream
,
const
block_t
*
p_block
)
int
httpd_StreamSend
(
httpd_stream_t
*
stream
,
const
block_t
*
p_block
)
{
if
(
p_block
==
NULL
||
p_block
->
p_buffer
==
NULL
)
{
if
(
!
p_block
||
!
p_block
->
p_buffer
)
return
VLC_SUCCESS
;
}
vlc_mutex_lock
(
&
stream
->
lock
);
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
)
{
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
);
httpd_AppendData
(
stream
,
p_block
->
p_buffer
,
p_block
->
i_buffer
);
vlc_mutex_unlock
(
&
stream
->
lock
);
vlc_mutex_unlock
(
&
stream
->
lock
);
return
VLC_SUCCESS
;
}
void
httpd_StreamDelete
(
httpd_stream_t
*
stream
)
void
httpd_StreamDelete
(
httpd_stream_t
*
stream
)
{
httpd_UrlDelete
(
stream
->
url
);
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
);
vlc_mutex_destroy
(
&
stream
->
lock
);
free
(
stream
->
psz_mime
);
free
(
stream
->
p_header
);
free
(
stream
->
p_buffer
);
free
(
stream
);
httpd_UrlDelete
(
stream
->
url
);
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
);
vlc_mutex_destroy
(
&
stream
->
lock
);
free
(
stream
->
psz_mime
);
free
(
stream
->
p_header
);
free
(
stream
->
p_buffer
);
free
(
stream
);
}
/*****************************************************************************
* Low level
*****************************************************************************/
static
void
*
httpd_HostThread
(
void
*
);
static
httpd_host_t
*
httpd_HostCreate
(
vlc_object_t
*
,
const
char
*
,
const
char
*
,
vlc_tls_creds_t
*
);
static
void
*
httpd_HostThread
(
void
*
);
static
httpd_host_t
*
httpd_HostCreate
(
vlc_object_t
*
,
const
char
*
,
const
char
*
,
vlc_tls_creds_t
*
);
/* create a new host */
httpd_host_t
*
vlc_http_HostNew
(
vlc_object_t
*
p_this
)
httpd_host_t
*
vlc_http_HostNew
(
vlc_object_t
*
p_this
)
{
return
httpd_HostCreate
(
p_this
,
"http-host"
,
"http-port"
,
NULL
);
return
httpd_HostCreate
(
p_this
,
"http-host"
,
"http-port"
,
NULL
);
}
httpd_host_t
*
vlc_https_HostNew
(
vlc_object_t
*
obj
)
httpd_host_t
*
vlc_https_HostNew
(
vlc_object_t
*
obj
)
{
char
*
cert
=
var_InheritString
(
obj
,
"http-cert"
);
if
(
cert
==
NULL
)
{
msg_Err
(
obj
,
"HTTP/TLS certificate not specified!"
);
char
*
cert
=
var_InheritString
(
obj
,
"http-cert"
);
if
(
!
cert
)
{
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
);
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
);
if
(
!
tls
)
{
msg_Err
(
obj
,
"HTTP/TLS certificate error (%s and %s)"
,
cert
,
key
?
key
:
cert
);
free
(
key
);
free
(
cert
);
return
NULL
;
}
free
(
key
);
free
(
cert
);
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
);
char
*
ca
=
var_InheritString
(
obj
,
"http-ca"
);
if
(
ca
)
{
if
(
vlc_tls_ServerAddCA
(
tls
,
ca
))
{
msg_Err
(
obj
,
"HTTP/TLS CA error (%s)"
,
ca
);
free
(
ca
);
goto
error
;
}
free
(
ca
);
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
);
char
*
crl
=
var_InheritString
(
obj
,
"http-crl"
);
if
(
crl
)
{
if
(
vlc_tls_ServerAddCRL
(
tls
,
crl
))
{
msg_Err
(
obj
,
"TLS CRL error (%s)"
,
crl
);
free
(
crl
);
goto
error
;
}
free
(
crl
);
free
(
crl
);
}
return
httpd_HostCreate
(
obj
,
"http-host"
,
"https-port"
,
tls
);
return
httpd_HostCreate
(
obj
,
"http-host"
,
"https-port"
,
tls
);
error:
vlc_tls_Delete
(
tls
);
vlc_tls_Delete
(
tls
);
return
NULL
;
}
httpd_host_t
*
vlc_rtsp_HostNew
(
vlc_object_t
*
p_this
)
httpd_host_t
*
vlc_rtsp_HostNew
(
vlc_object_t
*
p_this
)
{
return
httpd_HostCreate
(
p_this
,
"rtsp-host"
,
"rtsp-port"
,
NULL
);
return
httpd_HostCreate
(
p_this
,
"rtsp-host"
,
"rtsp-port"
,
NULL
);
}
static
struct
httpd
...
...
@@ -1008,73 +939,69 @@ static struct httpd
int
i_host
;
}
httpd
=
{
VLC_STATIC_MUTEX
,
NULL
,
0
};
static
httpd_host_t
*
httpd_HostCreate
(
vlc_object_t
*
p_this
,
static
httpd_host_t
*
httpd_HostCreate
(
vlc_object_t
*
p_this
,
const
char
*
hostvar
,
const
char
*
portvar
,
vlc_tls_creds_t
*
p_tls
)
vlc_tls_creds_t
*
p_tls
)
{
httpd_host_t
*
host
;
char
*
hostname
=
var_InheritString
(
p_this
,
hostvar
);
unsigned
port
=
var_InheritInteger
(
p_this
,
portvar
);
char
*
hostname
=
var_InheritString
(
p_this
,
hostvar
);
unsigned
port
=
var_InheritInteger
(
p_this
,
portvar
);
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
);
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
);
}
/* to be sure to avoid multiple creation */
vlc_mutex_lock
(
&
httpd
.
mutex
);
vlc_mutex_lock
(
&
httpd
.
mutex
);
/* verify if it already exist */
for
(
int
i
=
0
;
i
<
httpd
.
i_host
;
i
++
)
{
for
(
int
i
=
0
;
i
<
httpd
.
i_host
;
i
++
)
{
host
=
httpd
.
host
[
i
];
/* cannot mix TLS and non-TLS hosts */
if
(
host
->
port
!=
port
||
(
host
->
p_tls
!=
NULL
)
!=
(
p_tls
!=
NULL
)
)
if
(
host
->
port
!=
port
||
(
host
->
p_tls
!=
NULL
)
!=
(
p_tls
!=
NULL
))
continue
;
/* 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
);
vlc_mutex_lock
(
&
host
->
lock
);
host
->
i_ref
++
;
vlc_mutex_unlock
(
&
host
->
lock
);
vlc_mutex_unlock
(
&
host
->
lock
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
vlc_UrlClean
(
&
url
);
vlc_tls_Delete
(
p_tls
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
vlc_UrlClean
(
&
url
);
vlc_tls_Delete
(
p_tls
);
return
host
;
}
/* create the new host */
host
=
(
httpd_host_t
*
)
vlc_custom_create
(
p_this
,
sizeof
(
*
host
),
"http host"
);
if
(
host
==
NULL
)
host
=
(
httpd_host_t
*
)
vlc_custom_create
(
p_this
,
sizeof
(
*
host
),
"http host"
);
if
(
!
host
)
goto
error
;
vlc_mutex_init
(
&
host
->
lock
);
vlc_cond_init
(
&
host
->
wait
);
vlc_mutex_init
(
&
host
->
lock
);
vlc_cond_init
(
&
host
->
wait
);
host
->
i_ref
=
1
;
host
->
fds
=
net_ListenTCP
(
p_this
,
url
.
psz_host
,
port
);
if
(
host
->
fds
==
NULL
)
{
msg_Err
(
p_this
,
"cannot create socket(s) for HTTP host"
);
host
->
fds
=
net_ListenTCP
(
p_this
,
url
.
psz_host
,
port
);
if
(
!
host
->
fds
)
{
msg_Err
(
p_this
,
"cannot create socket(s) for HTTP host"
);
goto
error
;
}
for
(
host
->
nfd
=
0
;
host
->
fds
[
host
->
nfd
]
!=
-
1
;
host
->
nfd
++
);
if
(
vlc_object_waitpipe
(
VLC_OBJECT
(
host
)
)
==
-
1
)
{
msg_Err
(
host
,
"signaling pipe error: %s"
,
vlc_strerror_c
(
errno
)
);
if
(
vlc_object_waitpipe
(
VLC_OBJECT
(
host
))
==
-
1
)
{
msg_Err
(
host
,
"signaling pipe error: %s"
,
vlc_strerror_c
(
errno
));
goto
error
;
}
...
...
@@ -1086,170 +1013,159 @@ static httpd_host_t *httpd_HostCreate( vlc_object_t *p_this,
host
->
p_tls
=
p_tls
;
/* create the thread */
if
(
vlc_clone
(
&
host
->
thread
,
httpd_HostThread
,
host
,
VLC_THREAD_PRIORITY_LOW
)
)
{
msg_Err
(
p_this
,
"cannot spawn http host thread"
);
if
(
vlc_clone
(
&
host
->
thread
,
httpd_HostThread
,
host
,
VLC_THREAD_PRIORITY_LOW
))
{
msg_Err
(
p_this
,
"cannot spawn http host thread"
);
goto
error
;
}
/* now add it to httpd */
TAB_APPEND
(
httpd
.
i_host
,
httpd
.
host
,
host
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
TAB_APPEND
(
httpd
.
i_host
,
httpd
.
host
,
host
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
vlc_UrlClean
(
&
url
);
vlc_UrlClean
(
&
url
);
return
host
;
error:
vlc_mutex_unlock
(
&
httpd
.
mutex
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
if
(
host
!=
NULL
)
{
net_ListenClose
(
host
->
fds
);
vlc_cond_destroy
(
&
host
->
wait
);
vlc_mutex_destroy
(
&
host
->
lock
);
vlc_object_release
(
host
);
if
(
host
)
{
net_ListenClose
(
host
->
fds
);
vlc_cond_destroy
(
&
host
->
wait
);
vlc_mutex_destroy
(
&
host
->
lock
);
vlc_object_release
(
host
);
}
vlc_UrlClean
(
&
url
);
vlc_tls_Delete
(
p_tls
);
vlc_UrlClean
(
&
url
);
vlc_tls_Delete
(
p_tls
);
return
NULL
;
}
/* delete a host */
void
httpd_HostDelete
(
httpd_host_t
*
host
)
void
httpd_HostDelete
(
httpd_host_t
*
host
)
{
bool
delete
=
false
;
vlc_mutex_lock
(
&
httpd
.
mutex
);
vlc_mutex_lock
(
&
httpd
.
mutex
);
vlc_mutex_lock
(
&
host
->
lock
);
vlc_mutex_lock
(
&
host
->
lock
);
host
->
i_ref
--
;
if
(
host
->
i_ref
==
0
)
if
(
host
->
i_ref
==
0
)
delete
=
true
;
vlc_mutex_unlock
(
&
host
->
lock
);
if
(
!
delete
)
{
vlc_mutex_unlock
(
&
host
->
lock
);
if
(
!
delete
)
{
/* still used */
vlc_mutex_unlock
(
&
httpd
.
mutex
);
msg_Dbg
(
host
,
"httpd_HostDelete: host still in use"
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
msg_Dbg
(
host
,
"httpd_HostDelete: host still in use"
);
return
;
}
TAB_REMOVE
(
httpd
.
i_host
,
httpd
.
host
,
host
);
TAB_REMOVE
(
httpd
.
i_host
,
httpd
.
host
,
host
);
vlc_cancel
(
host
->
thread
);
vlc_join
(
host
->
thread
,
NULL
);
vlc_cancel
(
host
->
thread
);
vlc_join
(
host
->
thread
,
NULL
);
msg_Dbg
(
host
,
"HTTP host removed"
);
msg_Dbg
(
host
,
"HTTP host removed"
);
for
(
int
i
=
0
;
i
<
host
->
i_url
;
i
++
)
{
msg_Err
(
host
,
"url still registered: %s"
,
host
->
url
[
i
]
->
psz_url
);
}
for
(
int
i
=
0
;
i
<
host
->
i_client
;
i
++
)
{
for
(
int
i
=
0
;
i
<
host
->
i_url
;
i
++
)
msg_Err
(
host
,
"url still registered: %s"
,
host
->
url
[
i
]
->
psz_url
);
for
(
int
i
=
0
;
i
<
host
->
i_client
;
i
++
)
{
httpd_client_t
*
cl
=
host
->
client
[
i
];
msg_Warn
(
host
,
"client still connected"
);
httpd_ClientClean
(
cl
);
TAB_REMOVE
(
host
->
i_client
,
host
->
client
,
cl
);
free
(
cl
);
msg_Warn
(
host
,
"client still connected"
);
httpd_ClientClean
(
cl
);
TAB_REMOVE
(
host
->
i_client
,
host
->
client
,
cl
);
free
(
cl
);
i
--
;
/* TODO */
}
vlc_tls_Delete
(
host
->
p_tls
);
net_ListenClose
(
host
->
fds
);
vlc_cond_destroy
(
&
host
->
wait
);
vlc_mutex_destroy
(
&
host
->
lock
);
vlc_object_release
(
host
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
vlc_tls_Delete
(
host
->
p_tls
);
net_ListenClose
(
host
->
fds
);
vlc_cond_destroy
(
&
host
->
wait
);
vlc_mutex_destroy
(
&
host
->
lock
);
vlc_object_release
(
host
);
vlc_mutex_unlock
(
&
httpd
.
mutex
);
}
/* register a new url */
httpd_url_t
*
httpd_UrlNew
(
httpd_host_t
*
host
,
const
char
*
psz_url
,
const
char
*
psz_user
,
const
char
*
psz_password
)
httpd_url_t
*
httpd_UrlNew
(
httpd_host_t
*
host
,
const
char
*
psz_url
,
const
char
*
psz_user
,
const
char
*
psz_password
)
{
httpd_url_t
*
url
;
assert
(
psz_url
!=
NULL
);
assert
(
psz_url
);
vlc_mutex_lock
(
&
host
->
lock
);
for
(
int
i
=
0
;
i
<
host
->
i_url
;
i
++
)
{
if
(
!
strcmp
(
psz_url
,
host
->
url
[
i
]
->
psz_url
)
)
{
msg_Warn
(
host
,
"cannot add '%s' (url already defined)"
,
psz_url
);
vlc_mutex_unlock
(
&
host
->
lock
);
vlc_mutex_lock
(
&
host
->
lock
);
for
(
int
i
=
0
;
i
<
host
->
i_url
;
i
++
)
if
(
!
strcmp
(
psz_url
,
host
->
url
[
i
]
->
psz_url
))
{
msg_Warn
(
host
,
"cannot add '%s' (url already defined)"
,
psz_url
);
vlc_mutex_unlock
(
&
host
->
lock
);
return
NULL
;
}
}
url
=
xmalloc
(
sizeof
(
httpd_url_t
)
);
url
=
xmalloc
(
sizeof
(
httpd_url_t
)
);
url
->
host
=
host
;
vlc_mutex_init
(
&
url
->
lock
);
url
->
psz_url
=
strdup
(
psz_url
);
url
->
psz_user
=
strdup
(
psz_user
?
psz_user
:
""
);
url
->
psz_password
=
strdup
(
psz_password
?
psz_password
:
""
);
for
(
int
i
=
0
;
i
<
HTTPD_MSG_MAX
;
i
++
)
{
vlc_mutex_init
(
&
url
->
lock
);
url
->
psz_url
=
strdup
(
psz_url
);
url
->
psz_user
=
strdup
(
psz_user
?
psz_user
:
""
);
url
->
psz_password
=
strdup
(
psz_password
?
psz_password
:
""
);
for
(
int
i
=
0
;
i
<
HTTPD_MSG_MAX
;
i
++
)
{
url
->
catch
[
i
].
cb
=
NULL
;
url
->
catch
[
i
].
p_sys
=
NULL
;
}
TAB_APPEND
(
host
->
i_url
,
host
->
url
,
url
);
vlc_cond_signal
(
&
host
->
wait
);
vlc_mutex_unlock
(
&
host
->
lock
);
TAB_APPEND
(
host
->
i_url
,
host
->
url
,
url
);
vlc_cond_signal
(
&
host
->
wait
);
vlc_mutex_unlock
(
&
host
->
lock
);
return
url
;
}
/* register callback on a url */
int
httpd_UrlCatch
(
httpd_url_t
*
url
,
int
i_msg
,
httpd_callback_t
cb
,
httpd_callback_sys_t
*
p_sys
)
int
httpd_UrlCatch
(
httpd_url_t
*
url
,
int
i_msg
,
httpd_callback_t
cb
,
httpd_callback_sys_t
*
p_sys
)
{
vlc_mutex_lock
(
&
url
->
lock
);
vlc_mutex_lock
(
&
url
->
lock
);
url
->
catch
[
i_msg
].
cb
=
cb
;
url
->
catch
[
i_msg
].
p_sys
=
p_sys
;
vlc_mutex_unlock
(
&
url
->
lock
);
vlc_mutex_unlock
(
&
url
->
lock
);
return
VLC_SUCCESS
;
}
/* delete a url */
void
httpd_UrlDelete
(
httpd_url_t
*
url
)
void
httpd_UrlDelete
(
httpd_url_t
*
url
)
{
httpd_host_t
*
host
=
url
->
host
;
vlc_mutex_lock
(
&
host
->
lock
);
TAB_REMOVE
(
host
->
i_url
,
host
->
url
,
url
);
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
);
vlc_mutex_destroy
(
&
url
->
lock
);
free
(
url
->
psz_url
);
free
(
url
->
psz_user
);
free
(
url
->
psz_password
);
for
(
int
i
=
0
;
i
<
host
->
i_client
;
i
++
)
{
for
(
int
i
=
0
;
i
<
host
->
i_client
;
i
++
)
{
httpd_client_t
*
client
=
host
->
client
[
i
];
if
(
client
->
url
==
url
)
{
if
(
client
->
url
!=
url
)
continue
;
/* TODO complete it */
msg_Warn
(
host
,
"force closing connections"
);
httpd_ClientClean
(
client
);
TAB_REMOVE
(
host
->
i_client
,
host
->
client
,
client
);
free
(
client
);
msg_Warn
(
host
,
"force closing connections"
);
httpd_ClientClean
(
client
);
TAB_REMOVE
(
host
->
i_client
,
host
->
client
,
client
);
free
(
client
);
i
--
;
}
}
free
(
url
);
vlc_mutex_unlock
(
&
host
->
lock
);
free
(
url
);
vlc_mutex_unlock
(
&
host
->
lock
);
}
static
void
httpd_MsgInit
(
httpd_message_t
*
msg
)
static
void
httpd_MsgInit
(
httpd_message_t
*
msg
)
{
msg
->
cl
=
NULL
;
msg
->
i_type
=
HTTPD_MSG_NONE
;
...
...
@@ -1269,35 +1185,30 @@ static void httpd_MsgInit( httpd_message_t *msg )
msg
->
p_body
=
NULL
;
}
static
void
httpd_MsgClean
(
httpd_message_t
*
msg
)
static
void
httpd_MsgClean
(
httpd_message_t
*
msg
)
{
free
(
msg
->
psz_url
);
free
(
msg
->
psz_args
);
for
(
size_t
i
=
0
;
i
<
msg
->
i_headers
;
i
++
)
{
free
(
msg
->
p_headers
[
i
].
name
);
free
(
msg
->
p_headers
[
i
].
value
);
}
free
(
msg
->
p_headers
);
free
(
msg
->
p_body
);
httpd_MsgInit
(
msg
);
free
(
msg
->
psz_url
);
free
(
msg
->
psz_args
);
for
(
size_t
i
=
0
;
i
<
msg
->
i_headers
;
i
++
)
{
free
(
msg
->
p_headers
[
i
].
name
);
free
(
msg
->
p_headers
[
i
].
value
);
}
free
(
msg
->
p_headers
);
free
(
msg
->
p_body
);
httpd_MsgInit
(
msg
);
}
const
char
*
httpd_MsgGet
(
const
httpd_message_t
*
msg
,
const
char
*
name
)
const
char
*
httpd_MsgGet
(
const
httpd_message_t
*
msg
,
const
char
*
name
)
{
for
(
size_t
i
=
0
;
i
<
msg
->
i_headers
;
i
++
)
{
if
(
!
strcasecmp
(
msg
->
p_headers
[
i
].
name
,
name
))
{
for
(
size_t
i
=
0
;
i
<
msg
->
i_headers
;
i
++
)
if
(
!
strcasecmp
(
msg
->
p_headers
[
i
].
name
,
name
))
return
msg
->
p_headers
[
i
].
value
;
}
}
return
NULL
;
}
void
httpd_MsgAdd
(
httpd_message_t
*
msg
,
const
char
*
name
,
const
char
*
psz_value
,
...
)
void
httpd_MsgAdd
(
httpd_message_t
*
msg
,
const
char
*
name
,
const
char
*
psz_value
,
...
)
{
httpd_header
*
p_tmp
=
realloc
(
msg
->
p_headers
,
sizeof
(
httpd_header
)
*
(
msg
->
i_headers
+
1
));
httpd_header
*
p_tmp
=
realloc
(
msg
->
p_headers
,
sizeof
(
httpd_header
)
*
(
msg
->
i_headers
+
1
));
if
(
!
p_tmp
)
return
;
...
...
@@ -1311,11 +1222,11 @@ void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value
h
->
value
=
NULL
;
va_list
args
;
va_start
(
args
,
psz_value
);
va_start
(
args
,
psz_value
);
int
ret
=
us_vasprintf
(
&
h
->
value
,
psz_value
,
args
);
va_end
(
args
);
va_end
(
args
);
if
(
ret
==
-
1
)
{
if
(
ret
==
-
1
)
{
free
(
h
->
name
);
return
;
}
...
...
@@ -1323,61 +1234,60 @@ void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value
msg
->
i_headers
++
;
}
static
void
httpd_ClientInit
(
httpd_client_t
*
cl
,
mtime_t
now
)
static
void
httpd_ClientInit
(
httpd_client_t
*
cl
,
mtime_t
now
)
{
cl
->
i_state
=
HTTPD_CLIENT_RECEIVING
;
cl
->
i_activity_date
=
now
;
cl
->
i_activity_timeout
=
INT64_C
(
10000000
);
cl
->
i_buffer_size
=
HTTPD_CL_BUFSIZE
;
cl
->
i_buffer
=
0
;
cl
->
p_buffer
=
xmalloc
(
cl
->
i_buffer_size
);
cl
->
p_buffer
=
xmalloc
(
cl
->
i_buffer_size
);
cl
->
i_keyframe_wait_to_pass
=
-
1
;
cl
->
b_stream_mode
=
false
;
httpd_MsgInit
(
&
cl
->
query
);
httpd_MsgInit
(
&
cl
->
answer
);
httpd_MsgInit
(
&
cl
->
query
);
httpd_MsgInit
(
&
cl
->
answer
);
}
char
*
httpd_ClientIP
(
const
httpd_client_t
*
cl
,
char
*
ip
,
int
*
port
)
char
*
httpd_ClientIP
(
const
httpd_client_t
*
cl
,
char
*
ip
,
int
*
port
)
{
return
net_GetPeerAddress
(
cl
->
fd
,
ip
,
port
)
?
NULL
:
ip
;
return
net_GetPeerAddress
(
cl
->
fd
,
ip
,
port
)
?
NULL
:
ip
;
}
char
*
httpd_ServerIP
(
const
httpd_client_t
*
cl
,
char
*
ip
,
int
*
port
)
char
*
httpd_ServerIP
(
const
httpd_client_t
*
cl
,
char
*
ip
,
int
*
port
)
{
return
net_GetSockAddress
(
cl
->
fd
,
ip
,
port
)
?
NULL
:
ip
;
return
net_GetSockAddress
(
cl
->
fd
,
ip
,
port
)
?
NULL
:
ip
;
}
static
void
httpd_ClientClean
(
httpd_client_t
*
cl
)
static
void
httpd_ClientClean
(
httpd_client_t
*
cl
)
{
if
(
cl
->
fd
>=
0
)
{
if
(
cl
->
p_tls
!=
NULL
)
vlc_tls_SessionDelete
(
cl
->
p_tls
);
net_Close
(
cl
->
fd
);
if
(
cl
->
fd
>=
0
)
{
if
(
cl
->
p_tls
)
vlc_tls_SessionDelete
(
cl
->
p_tls
);
net_Close
(
cl
->
fd
);
cl
->
fd
=
-
1
;
}
httpd_MsgClean
(
&
cl
->
answer
);
httpd_MsgClean
(
&
cl
->
query
);
httpd_MsgClean
(
&
cl
->
answer
);
httpd_MsgClean
(
&
cl
->
query
);
free
(
cl
->
p_buffer
);
free
(
cl
->
p_buffer
);
cl
->
p_buffer
=
NULL
;
}
static
httpd_client_t
*
httpd_ClientNew
(
int
fd
,
vlc_tls_t
*
p_tls
,
mtime_t
now
)
static
httpd_client_t
*
httpd_ClientNew
(
int
fd
,
vlc_tls_t
*
p_tls
,
mtime_t
now
)
{
httpd_client_t
*
cl
=
malloc
(
sizeof
(
httpd_client_t
)
);
httpd_client_t
*
cl
=
malloc
(
sizeof
(
httpd_client_t
)
);
if
(
!
cl
)
return
NULL
;
if
(
!
cl
)
return
NULL
;
cl
->
i_ref
=
0
;
cl
->
fd
=
fd
;
cl
->
url
=
NULL
;
cl
->
p_tls
=
p_tls
;
httpd_ClientInit
(
cl
,
now
);
if
(
p_tls
!=
NULL
)
httpd_ClientInit
(
cl
,
now
);
if
(
p_tls
)
cl
->
i_state
=
HTTPD_CLIENT_TLS_HS_OUT
;
return
cl
;
...
...
@@ -1405,7 +1315,7 @@ ssize_t httpd_NetSend (httpd_client_t *cl, const uint8_t *p, size_t i_len)
p_tls
=
cl
->
p_tls
;
do
val
=
p_tls
?
tls_Send
(
p_tls
,
p
,
i_len
)
val
=
p_tls
?
tls_Send
(
p_tls
,
p
,
i_len
)
:
send
(
cl
->
fd
,
p
,
i_len
,
0
);
while
(
val
==
-
1
&&
errno
==
EINTR
);
return
val
;
...
...
@@ -1434,81 +1344,55 @@ msg_type[] =
};
static
void
httpd_ClientRecv
(
httpd_client_t
*
cl
)
static
void
httpd_ClientRecv
(
httpd_client_t
*
cl
)
{
int
i_len
;
/* ignore leading whites */
if
(
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_NONE
)
&&
(
cl
->
i_buffer
==
0
)
)
{
if
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_NONE
&&
cl
->
i_buffer
==
0
)
{
unsigned
char
c
;
i_len
=
httpd_NetRecv
(
cl
,
&
c
,
1
);
i_len
=
httpd_NetRecv
(
cl
,
&
c
,
1
);
if
(
(
i_len
>
0
)
&&
(
strchr
(
"
\r\n\t
"
,
c
)
==
NULL
)
)
{
if
(
i_len
>
0
&&
!
strchr
(
"
\r\n\t
"
,
c
))
{
cl
->
p_buffer
[
0
]
=
c
;
cl
->
i_buffer
++
;
}
}
else
if
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_NONE
)
{
}
else
if
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_NONE
)
{
/* enough to see if it's Interleaved RTP over RTSP or RTSP/HTTP */
i_len
=
httpd_NetRecv
(
cl
,
&
cl
->
p_buffer
[
cl
->
i_buffer
],
7
-
cl
->
i_buffer
);
if
(
i_len
>
0
)
{
i_len
=
httpd_NetRecv
(
cl
,
&
cl
->
p_buffer
[
cl
->
i_buffer
],
7
-
cl
->
i_buffer
);
if
(
i_len
>
0
)
cl
->
i_buffer
+=
i_len
;
}
/* The smallest legal request is 7 bytes ("GET /\r\n"),
* this is the maximum we can ask at this point. */
if
(
cl
->
i_buffer
>=
7
)
{
if
(
!
memcmp
(
cl
->
p_buffer
,
"HTTP/1."
,
7
)
)
{
if
(
cl
->
i_buffer
>=
7
)
{
if
(
!
memcmp
(
cl
->
p_buffer
,
"HTTP/1."
,
7
))
{
cl
->
query
.
i_proto
=
HTTPD_PROTO_HTTP
;
cl
->
query
.
i_type
=
HTTPD_MSG_ANSWER
;
}
else
if
(
!
memcmp
(
cl
->
p_buffer
,
"RTSP/1."
,
7
)
)
{
}
else
if
(
!
memcmp
(
cl
->
p_buffer
,
"RTSP/1."
,
7
))
{
cl
->
query
.
i_proto
=
HTTPD_PROTO_RTSP
;
cl
->
query
.
i_type
=
HTTPD_MSG_ANSWER
;
}
else
{
}
else
{
/* We need the full request line to determine the protocol. */
cl
->
query
.
i_proto
=
HTTPD_PROTO_HTTP0
;
cl
->
query
.
i_type
=
HTTPD_MSG_NONE
;
}
}
}
else
if
(
cl
->
query
.
i_body
>
0
)
{
}
else
if
(
cl
->
query
.
i_body
>
0
)
{
/* we are reading the body of a request or a channel */
i_len
=
httpd_NetRecv
(
cl
,
&
cl
->
query
.
p_body
[
cl
->
i_buffer
],
cl
->
query
.
i_body
-
cl
->
i_buffer
);
if
(
i_len
>
0
)
{
i_len
=
httpd_NetRecv
(
cl
,
&
cl
->
query
.
p_body
[
cl
->
i_buffer
],
cl
->
query
.
i_body
-
cl
->
i_buffer
);
if
(
i_len
>
0
)
cl
->
i_buffer
+=
i_len
;
}
if
(
cl
->
i_buffer
>=
cl
->
query
.
i_body
)
{
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
(
;;
)
{
if
(
cl
->
i_buffer
==
cl
->
i_buffer_size
)
{
uint8_t
*
newbuf
=
realloc
(
cl
->
p_buffer
,
cl
->
i_buffer_size
+
1024
);
if
(
newbuf
==
NULL
)
{
}
else
for
(;;)
{
/* we are reading a header -> char by char */
if
(
cl
->
i_buffer
==
cl
->
i_buffer_size
)
{
uint8_t
*
newbuf
=
realloc
(
cl
->
p_buffer
,
cl
->
i_buffer_size
+
1024
);
if
(
!
newbuf
)
{
i_len
=
0
;
break
;
}
...
...
@@ -1517,372 +1401,298 @@ static void httpd_ClientRecv( httpd_client_t *cl )
cl
->
i_buffer_size
+=
1024
;
}
i_len
=
httpd_NetRecv
(
cl
,
&
cl
->
p_buffer
[
cl
->
i_buffer
],
1
);
if
(
i_len
<=
0
)
{
i_len
=
httpd_NetRecv
(
cl
,
&
cl
->
p_buffer
[
cl
->
i_buffer
],
1
);
if
(
i_len
<=
0
)
break
;
}
cl
->
i_buffer
++
;
if
(
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_HTTP0
)
&&
(
cl
->
p_buffer
[
cl
->
i_buffer
-
1
]
==
'\n'
)
)
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
);
const
char
*
p
=
memchr
(
cl
->
p_buffer
,
' '
,
cl
->
i_buffer
);
size_t
len
;
assert
(
cl
->
query
.
i_type
==
HTTPD_MSG_NONE
);
assert
(
cl
->
query
.
i_type
==
HTTPD_MSG_NONE
);
if
(
p
==
NULL
)
/* no URI: evil guy */
{
if
(
!
p
)
{
/* no URI: evil guy */
i_len
=
0
;
/* drop connection */
break
;
}
do
p
++
;
/* skips extra spaces */
while
(
*
p
==
' '
);
while
(
*
p
==
' '
);
p
=
memchr
(
p
,
' '
,
((
char
*
)
cl
->
p_buffer
)
+
cl
->
i_buffer
-
p
);
if
(
p
==
NULL
)
/* no explicit protocol: HTTP/0.9 */
{
p
=
memchr
(
p
,
' '
,
((
char
*
)
cl
->
p_buffer
)
+
cl
->
i_buffer
-
p
);
if
(
!
p
)
{
/* no explicit protocol: HTTP/0.9 */
i_len
=
0
;
/* not supported currently -> drop */
break
;
}
do
p
++
;
/* skips extra spaces ever again */
while
(
*
p
==
' '
);
while
(
*
p
==
' '
);
len
=
((
char
*
)
cl
->
p_buffer
)
+
cl
->
i_buffer
-
p
;
if
(
len
<
7
)
/* foreign protocol */
if
(
len
<
7
)
/* foreign protocol */
i_len
=
0
;
/* I don't understand -> drop */
else
if
(
memcmp
(
p
,
"HTTP/1."
,
7
)
==
0
)
{
else
if
(
!
memcmp
(
p
,
"HTTP/1."
,
7
))
{
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_version
=
atoi
(
p
+
7
);
}
else
if
(
!
memcmp
(
p
,
"RTSP/1."
,
7
))
{
cl
->
query
.
i_proto
=
HTTPD_PROTO_RTSP
;
cl
->
query
.
i_version
=
atoi
(
p
+
7
);
}
else
if
(
memcmp
(
p
,
"HTTP/"
,
5
)
==
0
)
{
cl
->
query
.
i_version
=
atoi
(
p
+
7
);
}
else
if
(
!
memcmp
(
p
,
"HTTP/"
,
5
))
{
const
uint8_t
sorry
[]
=
"HTTP/1.1 505 Unknown HTTP version
\r\n\r\n
"
;
httpd_NetSend
(
cl
,
sorry
,
sizeof
(
sorry
)
-
1
);
httpd_NetSend
(
cl
,
sorry
,
sizeof
(
sorry
)
-
1
);
i_len
=
0
;
/* drop */
}
else
if
(
memcmp
(
p
,
"RTSP/"
,
5
)
==
0
)
{
}
else
if
(
!
memcmp
(
p
,
"RTSP/"
,
5
))
{
const
uint8_t
sorry
[]
=
"RTSP/1.0 505 Unknown RTSP version
\r\n\r\n
"
;
httpd_NetSend
(
cl
,
sorry
,
sizeof
(
sorry
)
-
1
);
httpd_NetSend
(
cl
,
sorry
,
sizeof
(
sorry
)
-
1
);
i_len
=
0
;
/* drop */
}
else
/* yet another foreign protocol */
}
else
/* yet another foreign protocol */
i_len
=
0
;
if
(
i_len
==
0
)
if
(
i_len
==
0
)
break
;
}
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
)
)
)
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
))
)
{
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
)
{
if
(
cl
->
query
.
i_type
==
HTTPD_MSG_ANSWER
)
{
/* FIXME:
* assume strlen( "HTTP/1.x"
) = 8
* assume strlen("HTTP/1.x"
) = 8
*/
cl
->
query
.
i_status
=
strtol
(
(
char
*
)
&
cl
->
p_buffer
[
8
],
&
p
,
0
);
while
(
*
p
==
' '
)
strtol
(
(
char
*
)
&
cl
->
p_buffer
[
8
],
&
p
,
0
);
while
(
*
p
==
' '
)
p
++
;
}
else
{
}
else
{
p
=
NULL
;
cl
->
query
.
i_type
=
HTTPD_MSG_NONE
;
for
(
unsigned
i
=
0
;
msg_type
[
i
].
name
[
0
];
i
++
)
{
if
(
!
strncmp
(
(
char
*
)
cl
->
p_buffer
,
msg_type
[
i
].
name
,
strlen
(
msg_type
[
i
].
name
)
)
)
{
for
(
unsigned
i
=
0
;
msg_type
[
i
].
name
[
0
];
i
++
)
if
(
!
strncmp
((
char
*
)
cl
->
p_buffer
,
msg_type
[
i
].
name
,
strlen
(
msg_type
[
i
].
name
)))
{
p
=
(
char
*
)
&
cl
->
p_buffer
[
strlen
(
msg_type
[
i
].
name
)
+
1
];
cl
->
query
.
i_type
=
msg_type
[
i
].
i_type
;
if
(
cl
->
query
.
i_proto
!=
msg_type
[
i
].
i_proto
)
{
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
)
{
if
(
strstr
(
(
char
*
)
cl
->
p_buffer
,
"HTTP/1."
)
)
{
if
(
!
p
)
{
if
(
strstr
((
char
*
)
cl
->
p_buffer
,
"HTTP/1."
))
cl
->
query
.
i_proto
=
HTTPD_PROTO_HTTP
;
}
else
if
(
strstr
(
(
char
*
)
cl
->
p_buffer
,
"RTSP/1."
)
)
{
else
if
(
strstr
((
char
*
)
cl
->
p_buffer
,
"RTSP/1."
))
cl
->
query
.
i_proto
=
HTTPD_PROTO_RTSP
;
}
}
else
{
}
else
{
char
*
p2
;
char
*
p3
;
while
(
*
p
==
' '
)
{
while
(
*
p
==
' '
)
p
++
;
}
p2
=
strchr
(
p
,
' '
);
if
(
p2
)
{
p2
=
strchr
(
p
,
' '
);
if
(
p2
)
*
p2
++
=
'\0'
;
}
if
(
!
strncasecmp
(
p
,
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_HTTP
)
?
"http:"
:
"rtsp:"
,
5
)
)
{
/* Skip hier-part of URL (if present) */
if
(
!
strncasecmp
(
p
,
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_HTTP
)
?
"http:"
:
"rtsp:"
,
5
))
{
/* Skip hier-part of URL (if present) */
p
+=
5
;
if
(
!
strncmp
(
p
,
"//"
,
2
)
)
/* skip authority */
{
/* see RFC3986 §3.2 */
if
(
!
strncmp
(
p
,
"//"
,
2
))
{
/* skip authority */
/* see RFC3986 §3.2 */
p
+=
2
;
p
+=
strcspn
(
p
,
"/?#"
);
p
+=
strcspn
(
p
,
"/?#"
);
}
}
else
if
(
!
strncasecmp
(
p
,
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_HTTP
)
?
"https:"
:
"rtsps:"
,
6
)
)
{
/* Skip hier-part of URL (if present) */
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 */
if
(
!
strncmp
(
p
,
"//"
,
2
))
{
/* skip authority */
/* see RFC3986 §3.2 */
p
+=
2
;
p
+=
strcspn
(
p
,
"/?#"
);
p
+=
strcspn
(
p
,
"/?#"
);
}
}
cl
->
query
.
psz_url
=
strdup
(
p
);
if
(
(
p3
=
strchr
(
cl
->
query
.
psz_url
,
'?'
)
)
)
{
cl
->
query
.
psz_url
=
strdup
(
p
);
if
((
p3
=
strchr
(
cl
->
query
.
psz_url
,
'?'
))
)
{
*
p3
++
=
'\0'
;
cl
->
query
.
psz_args
=
(
uint8_t
*
)
strdup
(
p3
);
cl
->
query
.
psz_args
=
(
uint8_t
*
)
strdup
(
p3
);
}
p
=
p2
;
}
}
if
(
p
)
{
p
=
strchr
(
p
,
'\n'
);
}
if
(
p
)
{
while
(
*
p
==
'\n'
||
*
p
==
'\r'
)
{
if
(
p
)
p
=
strchr
(
p
,
'\n'
);
if
(
p
)
{
while
(
*
p
==
'\n'
||
*
p
==
'\r'
)
p
++
;
}
while
(
p
&&
*
p
!=
'\0'
)
{
while
(
p
&&
*
p
)
{
char
*
line
=
p
;
char
*
eol
=
p
=
strchr
(
p
,
'\n'
);
char
*
eol
=
p
=
strchr
(
p
,
'\n'
);
char
*
colon
;
while
(
eol
&&
eol
>=
line
&&
(
*
eol
==
'\n'
||
*
eol
==
'\r'
)
)
{
while
(
eol
&&
eol
>=
line
&&
(
*
eol
==
'\n'
||
*
eol
==
'\r'
))
*
eol
--
=
'\0'
;
}
if
(
(
colon
=
strchr
(
line
,
':'
)
)
)
{
if
((
colon
=
strchr
(
line
,
':'
)))
{
*
colon
++
=
'\0'
;
while
(
*
colon
==
' '
)
{
while
(
*
colon
==
' '
)
colon
++
;
}
httpd_MsgAdd
(
&
cl
->
query
,
line
,
colon
);
httpd_MsgAdd
(
&
cl
->
query
,
line
,
colon
);
if
(
!
strcasecmp
(
line
,
"Content-Length"
)
)
{
cl
->
query
.
i_body
=
atol
(
colon
);
}
if
(
!
strcasecmp
(
line
,
"Content-Length"
))
cl
->
query
.
i_body
=
atol
(
colon
);
}
if
(
p
)
{
if
(
p
)
{
p
++
;
while
(
*
p
==
'\n'
||
*
p
==
'\r'
)
{
while
(
*
p
==
'\n'
||
*
p
==
'\r'
)
p
++
;
}
}
}
}
if
(
cl
->
query
.
i_body
>
0
)
{
if
(
cl
->
query
.
i_body
>
0
)
{
/* 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) */
cl
->
query
.
p_body
=
malloc
(
cl
->
query
.
i_body
);
cl
->
query
.
p_body
=
malloc
(
cl
->
query
.
i_body
);
cl
->
i_buffer
=
0
;
if
(
cl
->
query
.
p_body
==
NULL
)
{
if
(
!
cl
->
query
.
p_body
)
{
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
);
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
);
httpd_NetSend
(
cl
,
sorry
,
sizeof
(
sorry
)
-
1
);
break
;
}
default:
assert
(
0
);
assert
(
0
);
}
i_len
=
0
;
/* drop */
}
break
;
}
else
{
}
else
cl
->
i_state
=
HTTPD_CLIENT_RECEIVE_DONE
;
}
}
}
}
/* check if the client is to be set to dead */
#if defined(
_WIN32
)
if
(
(
i_len
<
0
&&
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
||
(
i_len
==
0
)
)
#if defined(
_WIN32
)
if
((
i_len
<
0
&&
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
||
(
i_len
==
0
)
)
#else
if
(
(
i_len
<
0
&&
errno
!=
EAGAIN
)
||
(
i_len
==
0
)
)
if
((
i_len
<
0
&&
errno
!=
EAGAIN
)
||
(
i_len
==
0
)
)
#endif
{
if
(
cl
->
query
.
i_proto
!=
HTTPD_PROTO_NONE
&&
cl
->
query
.
i_type
!=
HTTPD_MSG_NONE
)
{
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
)
{
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
;
}
}
/* XXX: for QT I have to disable timeout. Try to find why */
if
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_RTSP
)
if
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_RTSP
)
cl
->
i_activity_timeout
=
0
;
}
static
void
httpd_ClientSend
(
httpd_client_t
*
cl
)
static
void
httpd_ClientSend
(
httpd_client_t
*
cl
)
{
int
i_len
;
if
(
cl
->
i_buffer
<
0
)
{
if
(
cl
->
i_buffer
<
0
)
{
/* We need to create the header */
int
i_size
=
0
;
char
*
p
;
const
char
*
psz_status
=
httpd_ReasonFromCode
(
cl
->
answer
.
i_status
);
const
char
*
psz_status
=
httpd_ReasonFromCode
(
cl
->
answer
.
i_status
);
i_size
=
strlen
(
"HTTP/1."
)
+
10
+
10
+
strlen
(
psz_status
)
+
5
;
for
(
size_t
i
=
0
;
i
<
cl
->
answer
.
i_headers
;
i
++
)
{
i_size
+=
strlen
(
cl
->
answer
.
p_headers
[
i
].
name
)
+
2
+
strlen
(
cl
->
answer
.
p_headers
[
i
].
value
)
+
2
;
}
i_size
=
strlen
(
"HTTP/1."
)
+
10
+
10
+
strlen
(
psz_status
)
+
5
;
for
(
size_t
i
=
0
;
i
<
cl
->
answer
.
i_headers
;
i
++
)
i_size
+=
strlen
(
cl
->
answer
.
p_headers
[
i
].
name
)
+
2
+
strlen
(
cl
->
answer
.
p_headers
[
i
].
value
)
+
2
;
if
(
cl
->
i_buffer_size
<
i_size
)
{
if
(
cl
->
i_buffer_size
<
i_size
)
{
cl
->
i_buffer_size
=
i_size
;
free
(
cl
->
p_buffer
);
cl
->
p_buffer
=
xmalloc
(
i_size
);
free
(
cl
->
p_buffer
);
cl
->
p_buffer
=
xmalloc
(
i_size
);
}
p
=
(
char
*
)
cl
->
p_buffer
;
p
+=
sprintf
(
p
,
"%s.%u %d %s
\r\n
"
,
p
+=
sprintf
(
p
,
"%s.%u %d %s
\r\n
"
,
cl
->
answer
.
i_proto
==
HTTPD_PROTO_HTTP
?
"HTTP/1"
:
"RTSP/1"
,
cl
->
answer
.
i_version
,
cl
->
answer
.
i_status
,
psz_status
);
for
(
size_t
i
=
0
;
i
<
cl
->
answer
.
i_headers
;
i
++
)
{
p
+=
sprintf
(
p
,
"%s: %s
\r\n
"
,
cl
->
answer
.
p_headers
[
i
].
name
,
cl
->
answer
.
p_headers
[
i
].
value
);
}
p
+=
sprintf
(
p
,
"
\r\n
"
);
cl
->
answer
.
i_status
,
psz_status
);
for
(
size_t
i
=
0
;
i
<
cl
->
answer
.
i_headers
;
i
++
)
p
+=
sprintf
(
p
,
"%s: %s
\r\n
"
,
cl
->
answer
.
p_headers
[
i
].
name
,
cl
->
answer
.
p_headers
[
i
].
value
);
p
+=
sprintf
(
p
,
"
\r\n
"
);
cl
->
i_buffer
=
0
;
cl
->
i_buffer_size
=
(
uint8_t
*
)
p
-
cl
->
p_buffer
;
}
i_len
=
httpd_NetSend
(
cl
,
&
cl
->
p_buffer
[
cl
->
i_buffer
],
cl
->
i_buffer_size
-
cl
->
i_buffer
);
if
(
i_len
>=
0
)
{
i_len
=
httpd_NetSend
(
cl
,
&
cl
->
p_buffer
[
cl
->
i_buffer
],
cl
->
i_buffer_size
-
cl
->
i_buffer
);
if
(
i_len
>=
0
)
{
cl
->
i_buffer
+=
i_len
;
if
(
cl
->
i_buffer
>=
cl
->
i_buffer_size
)
{
if
(
cl
->
answer
.
i_body
==
0
&&
cl
->
answer
.
i_body_offset
>
0
)
{
if
(
cl
->
i_buffer
>=
cl
->
i_buffer_size
)
{
if
(
cl
->
answer
.
i_body
==
0
&&
cl
->
answer
.
i_body_offset
>
0
)
{
/* catch more body data */
int
i_msg
=
cl
->
query
.
i_type
;
int64_t
i_offset
=
cl
->
answer
.
i_body_offset
;
httpd_MsgClean
(
&
cl
->
answer
);
httpd_MsgClean
(
&
cl
->
answer
);
cl
->
answer
.
i_body_offset
=
i_offset
;
cl
->
url
->
catch
[
i_msg
].
cb
(
cl
->
url
->
catch
[
i_msg
].
p_sys
,
cl
,
&
cl
->
answer
,
&
cl
->
query
);
cl
->
url
->
catch
[
i_msg
].
cb
(
cl
->
url
->
catch
[
i_msg
].
p_sys
,
cl
,
&
cl
->
answer
,
&
cl
->
query
);
}
if
(
cl
->
answer
.
i_body
>
0
)
{
if
(
cl
->
answer
.
i_body
>
0
)
{
/* send the body data */
free
(
cl
->
p_buffer
);
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 */
}
else
/* send finished */
cl
->
i_state
=
HTTPD_CLIENT_SEND_DONE
;
}
}
}
else
{
#if defined( _WIN32 )
if
(
(
i_len
<
0
&&
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
||
(
i_len
==
0
)
)
}
else
{
#if defined(_WIN32)
if
((
i_len
<
0
&&
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
||
(
i_len
==
0
))
#else
if
(
(
i_len
<
0
&&
errno
!=
EAGAIN
)
||
(
i_len
==
0
)
)
if
((
i_len
<
0
&&
errno
!=
EAGAIN
)
||
(
i_len
==
0
)
)
#endif
{
/* error */
...
...
@@ -1891,9 +1701,9 @@ static void httpd_ClientSend( httpd_client_t *cl )
}
}
static
void
httpd_ClientTlsHandshake
(
httpd_client_t
*
cl
)
static
void
httpd_ClientTlsHandshake
(
httpd_client_t
*
cl
)
{
switch
(
vlc_tls_SessionHandshake
(
cl
->
p_tls
,
NULL
,
NULL
)
)
{
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
;
...
...
@@ -1933,11 +1743,11 @@ static bool httpdAuthOk(const char *user, const char *pass, const char *b64)
if
(
strcmp
(
given_pass
,
pass
))
goto
auth_failed
;
free
(
given_user
);
free
(
given_user
);
return
true
;
auth_failed:
free
(
given_user
);
free
(
given_user
);
return
false
;
}
...
...
@@ -1945,18 +1755,16 @@ static void httpdLoop(httpd_host_t *host)
{
struct
pollfd
ufd
[
host
->
nfd
+
host
->
i_client
];
unsigned
nfd
;
for
(
nfd
=
0
;
nfd
<
host
->
nfd
;
nfd
++
)
{
for
(
nfd
=
0
;
nfd
<
host
->
nfd
;
nfd
++
)
{
ufd
[
nfd
].
fd
=
host
->
fds
[
nfd
];
ufd
[
nfd
].
events
=
POLLIN
;
ufd
[
nfd
].
revents
=
0
;
}
/* 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
);
while
(
host
->
i_url
<=
0
)
{
mutex_cleanup_push
(
&
host
->
lock
);
vlc_cond_wait
(
&
host
->
wait
,
&
host
->
lock
);
vlc_cleanup_pop
();
}
...
...
@@ -1964,18 +1772,16 @@ static void httpdLoop(httpd_host_t *host)
bool
b_low_delay
=
false
;
int
canc
=
vlc_savecancel
();
for
(
int
i_client
=
0
;
i_client
<
host
->
i_client
;
i_client
++
)
{
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
)
)
)
)
{
httpd_ClientClean
(
cl
);
TAB_REMOVE
(
host
->
i_client
,
host
->
client
,
cl
);
free
(
cl
);
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
))))
{
httpd_ClientClean
(
cl
);
TAB_REMOVE
(
host
->
i_client
,
host
->
client
,
cl
);
free
(
cl
);
i_client
--
;
continue
;
}
...
...
@@ -2001,7 +1807,7 @@ static void httpdLoop(httpd_host_t *host)
httpd_message_t
*
answer
=
&
cl
->
answer
;
httpd_message_t
*
query
=
&
cl
->
query
;
httpd_MsgInit
(
answer
);
httpd_MsgInit
(
answer
);
/* Handle what we received */
switch
(
query
->
i_type
)
{
...
...
@@ -2017,11 +1823,10 @@ static void httpdLoop(httpd_host_t *host)
answer
->
i_body
=
0
;
answer
->
p_body
=
NULL
;
httpd_MsgAdd
(
answer
,
"Server"
,
"VLC/%s"
,
VERSION
);
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"0"
);
httpd_MsgAdd
(
answer
,
"Server"
,
"VLC/%s"
,
VERSION
);
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"0"
);
switch
(
query
->
i_proto
)
{
switch
(
query
->
i_proto
)
{
case
HTTPD_PROTO_HTTP
:
answer
->
i_version
=
1
;
httpd_MsgAdd
(
answer
,
"Allow"
,
"GET,HEAD,POST,OPTIONS"
);
...
...
@@ -2030,21 +1835,21 @@ static void httpdLoop(httpd_host_t *host)
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
);
const
char
*
p
=
httpd_MsgGet
(
query
,
"Cseq"
);
if
(
p
)
httpd_MsgAdd
(
answer
,
"Cseq"
,
"%s"
,
p
);
p
=
httpd_MsgGet
(
query
,
"Timestamp"
);
if
(
p
)
httpd_MsgAdd
(
answer
,
"Timestamp"
,
"%s"
,
p
);
p
=
httpd_MsgGet
(
query
,
"Require"
);
if
(
p
!=
NULL
)
{
p
=
httpd_MsgGet
(
query
,
"Require"
);
if
(
p
)
{
answer
->
i_status
=
551
;
httpd_MsgAdd
(
query
,
"Unsupported"
,
"%s"
,
p
);
httpd_MsgAdd
(
query
,
"Unsupported"
,
"%s"
,
p
);
}
httpd_MsgAdd
(
answer
,
"Public"
,
"DESCRIBE,SETUP,"
"TEARDOWN,PLAY,PAUSE,GET_PARAMETER"
);
httpd_MsgAdd
(
answer
,
"Public"
,
"DESCRIBE,SETUP,"
"TEARDOWN,PLAY,PAUSE,GET_PARAMETER"
);
break
;
}
...
...
@@ -2054,7 +1859,7 @@ static void httpdLoop(httpd_host_t *host)
break
;
case
HTTPD_MSG_NONE
:
if
(
query
->
i_proto
==
HTTPD_PROTO_NONE
)
{
if
(
query
->
i_proto
==
HTTPD_PROTO_NONE
)
{
cl
->
url
=
NULL
;
cl
->
i_state
=
HTTPD_CLIENT_DEAD
;
}
else
{
...
...
@@ -2067,7 +1872,7 @@ static void httpdLoop(httpd_host_t *host)
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
);
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
;
...
...
@@ -2079,7 +1884,7 @@ static void httpdLoop(httpd_host_t *host)
bool
b_auth_failed
=
false
;
/* Search the url and trigger callbacks */
for
(
int
i
=
0
;
i
<
host
->
i_url
;
i
++
)
{
for
(
int
i
=
0
;
i
<
host
->
i_url
;
i
++
)
{
httpd_url_t
*
url
=
host
->
url
[
i
];
if
(
strcmp
(
url
->
psz_url
,
query
->
psz_url
))
...
...
@@ -2098,25 +1903,25 @@ static void httpdLoop(httpd_host_t *host)
if
(
url
->
catch
[
i_msg
].
cb
(
url
->
catch
[
i_msg
].
p_sys
,
cl
,
answer
,
query
))
continue
;
if
(
answer
->
i_proto
==
HTTPD_PROTO_NONE
)
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
)
if
(
!
cl
->
url
)
cl
->
url
=
url
;
}
if
(
answer
)
{
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
\"
"
);
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 */
...
...
@@ -2127,8 +1932,8 @@ static void httpdLoop(httpd_host_t *host)
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"
);
httpd_MsgAdd
(
answer
,
"Content-Length"
,
"%d"
,
answer
->
i_body
);
httpd_MsgAdd
(
answer
,
"Content-Type"
,
"%s"
,
"text/html"
);
}
cl
->
i_state
=
HTTPD_CLIENT_SENDING
;
...
...
@@ -2138,54 +1943,44 @@ static void httpdLoop(httpd_host_t *host)
}
case
HTTPD_CLIENT_SEND_DONE
:
if
(
!
cl
->
b_stream_mode
||
cl
->
answer
.
i_body_offset
==
0
)
{
const
char
*
psz_connection
=
httpd_MsgGet
(
&
cl
->
answer
,
"Connection"
);
const
char
*
psz_query
=
httpd_MsgGet
(
&
cl
->
query
,
"Connection"
);
if
(
!
cl
->
b_stream_mode
||
cl
->
answer
.
i_body_offset
==
0
)
{
const
char
*
psz_connection
=
httpd_MsgGet
(
&
cl
->
answer
,
"Connection"
);
const
char
*
psz_query
=
httpd_MsgGet
(
&
cl
->
query
,
"Connection"
);
bool
b_connection
=
false
;
bool
b_keepalive
=
false
;
bool
b_query
=
false
;
cl
->
url
=
NULL
;
if
(
psz_connection
)
{
b_connection
=
(
strcasecmp
(
psz_connection
,
"Close"
)
==
0
);
b_keepalive
=
(
strcasecmp
(
psz_connection
,
"Keep-Alive"
)
==
0
);
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
(
psz_query
)
b_query
=
(
strcasecmp
(
psz_query
,
"Close"
)
==
0
);
if
(
(
(
cl
->
query
.
i_proto
==
HTTPD_PROTO_HTTP
)
&&
(
(
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
)
)
{
httpd_MsgClean
(
&
cl
->
query
);
httpd_MsgInit
(
&
cl
->
query
);
if
(((
cl
->
query
.
i_proto
==
HTTPD_PROTO_HTTP
)
&&
((
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
))
{
httpd_MsgClean
(
&
cl
->
query
);
httpd_MsgInit
(
&
cl
->
query
);
cl
->
i_buffer
=
0
;
cl
->
i_buffer_size
=
1000
;
free
(
cl
->
p_buffer
);
cl
->
p_buffer
=
xmalloc
(
cl
->
i_buffer_size
);
free
(
cl
->
p_buffer
);
cl
->
p_buffer
=
xmalloc
(
cl
->
i_buffer_size
);
cl
->
i_state
=
HTTPD_CLIENT_RECEIVING
;
}
else
{
}
else
cl
->
i_state
=
HTTPD_CLIENT_DEAD
;
}
httpd_MsgClean
(
&
cl
->
answer
);
}
else
{
httpd_MsgClean
(
&
cl
->
answer
);
}
else
{
i_offset
=
cl
->
answer
.
i_body_offset
;
httpd_MsgClean
(
&
cl
->
answer
);
httpd_MsgClean
(
&
cl
->
answer
);
cl
->
answer
.
i_body_offset
=
i_offset
;
free
(
cl
->
p_buffer
);
free
(
cl
->
p_buffer
);
cl
->
p_buffer
=
NULL
;
cl
->
i_buffer
=
0
;
cl
->
i_buffer_size
=
0
;
...
...
@@ -2198,13 +1993,12 @@ static void httpdLoop(httpd_host_t *host)
i_offset
=
cl
->
answer
.
i_body_offset
;
int
i_msg
=
cl
->
query
.
i_type
;
httpd_MsgInit
(
&
cl
->
answer
);
httpd_MsgInit
(
&
cl
->
answer
);
cl
->
answer
.
i_body_offset
=
i_offset
;
cl
->
url
->
catch
[
i_msg
].
cb
(
cl
->
url
->
catch
[
i_msg
].
p_sys
,
cl
,
&
cl
->
answer
,
&
cl
->
query
);
if
(
cl
->
answer
.
i_type
!=
HTTPD_MSG_NONE
)
{
cl
->
url
->
catch
[
i_msg
].
cb
(
cl
->
url
->
catch
[
i_msg
].
p_sys
,
cl
,
&
cl
->
answer
,
&
cl
->
query
);
if
(
cl
->
answer
.
i_type
!=
HTTPD_MSG_NONE
)
{
/* we have new data, so re-enter send mode */
cl
->
i_buffer
=
0
;
cl
->
p_buffer
=
cl
->
answer
.
p_body
;
...
...
@@ -2220,23 +2014,23 @@ static void httpdLoop(httpd_host_t *host)
else
b_low_delay
=
true
;
}
vlc_mutex_unlock
(
&
host
->
lock
);
vlc_restorecancel
(
canc
);
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
);
int
ret
=
poll
(
ufd
,
nfd
,
b_low_delay
?
20
:
-
1
);
canc
=
vlc_savecancel
();
vlc_mutex_lock
(
&
host
->
lock
);
switch
(
ret
)
{
vlc_mutex_lock
(
&
host
->
lock
);
switch
(
ret
)
{
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
);
msg_Err
(
host
,
"polling error: %s"
,
vlc_strerror_c
(
errno
)
);
msleep
(
100000
);
}
case
0
:
vlc_restorecancel
(
canc
);
vlc_restorecancel
(
canc
);
return
;
}
...
...
@@ -2244,38 +2038,36 @@ static void httpdLoop(httpd_host_t *host)
now
=
mdate
();
nfd
=
host
->
nfd
;
for
(
int
i_client
=
0
;
i_client
<
host
->
i_client
;
i_client
++
)
{
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
];
assert
(
pufd
<
&
ufd
[
sizeof
(
ufd
)
/
sizeof
(
ufd
[
0
])]
);
assert
(
pufd
<
&
ufd
[
sizeof
(
ufd
)
/
sizeof
(
ufd
[
0
])]
);
if
(
cl
->
fd
!=
pufd
->
fd
)
if
(
cl
->
fd
!=
pufd
->
fd
)
continue
;
// we were not waiting for this client
++
nfd
;
if
(
pufd
->
revents
==
0
)
if
(
pufd
->
revents
==
0
)
continue
;
// no event received
cl
->
i_activity_date
=
now
;
switch
(
cl
->
i_state
)
{
case
HTTPD_CLIENT_RECEIVING
:
httpd_ClientRecv
(
cl
);
break
;
case
HTTPD_CLIENT_SENDING
:
httpd_ClientSend
(
cl
);
break
;
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
;
case
HTTPD_CLIENT_TLS_HS_OUT
:
httpd_ClientTlsHandshake
(
cl
);
break
;
}
}
/* Handle server sockets (accept new connections) */
for
(
nfd
=
0
;
nfd
<
host
->
nfd
;
nfd
++
)
{
for
(
nfd
=
0
;
nfd
<
host
->
nfd
;
nfd
++
)
{
httpd_client_t
*
cl
;
int
fd
=
ufd
[
nfd
].
fd
;
assert
(
fd
==
host
->
fds
[
nfd
]);
if
(
ufd
[
nfd
].
revents
==
0
)
if
(
ufd
[
nfd
].
revents
==
0
)
continue
;
/* */
...
...
@@ -2287,80 +2079,74 @@ static void httpdLoop(httpd_host_t *host)
vlc_tls_t
*
p_tls
;
if
(
host
->
p_tls
!=
NULL
)
p_tls
=
vlc_tls_SessionCreate
(
host
->
p_tls
,
fd
,
NULL
);
if
(
host
->
p_tls
)
p_tls
=
vlc_tls_SessionCreate
(
host
->
p_tls
,
fd
,
NULL
);
else
p_tls
=
NULL
;
cl
=
httpd_ClientNew
(
fd
,
p_tls
,
now
);
cl
=
httpd_ClientNew
(
fd
,
p_tls
,
now
);
TAB_APPEND
(
host
->
i_client
,
host
->
client
,
cl
);
TAB_APPEND
(
host
->
i_client
,
host
->
client
,
cl
);
}
vlc_restorecancel
(
canc
);
}
static
void
*
httpd_HostThread
(
void
*
data
)
static
void
*
httpd_HostThread
(
void
*
data
)
{
httpd_host_t
*
host
=
data
;
vlc_mutex_lock
(
&
host
->
lock
);
while
(
host
->
i_ref
>
0
)
vlc_mutex_lock
(
&
host
->
lock
);
while
(
host
->
i_ref
>
0
)
httpdLoop
(
host
);
vlc_mutex_unlock
(
&
host
->
lock
);
vlc_mutex_unlock
(
&
host
->
lock
);
return
NULL
;
}
int
httpd_StreamSetHTTPHeaders
(
httpd_stream_t
*
p_stream
,
httpd_header
*
p_headers
,
size_t
i_headers
)
int
httpd_StreamSetHTTPHeaders
(
httpd_stream_t
*
p_stream
,
httpd_header
*
p_headers
,
size_t
i_headers
)
{
if
(
!
p_stream
)
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
);
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
);
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
);
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
);
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
)
)
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
);
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
);
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
);
vlc_mutex_unlock
(
&
p_stream
->
lock
);
return
VLC_SUCCESS
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment