Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
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
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