Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dlib
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
钟尚武
dlib
Commits
1db057d6
Commit
1db057d6
authored
Nov 07, 2012
by
Davis King
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored the code in the http server so that it will be more reusable
by other tools.
parent
05b1ba8b
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
183 additions
and
111 deletions
+183
-111
server_http_1.h
dlib/server/server_http_1.h
+181
-110
server_http_abstract.h
dlib/server/server_http_abstract.h
+2
-1
No files found.
dlib/server/server_http_1.h
View file @
1db057d6
...
@@ -25,34 +25,18 @@
...
@@ -25,34 +25,18 @@
namespace
dlib
namespace
dlib
{
{
template
<
// ----------------------------------------------------------------------------------------
typename
server_base
>
class
server_http_1
:
public
server_base
{
/*!
CONVENTION
this extension doesn't add any new state to this object.
!*/
public
:
class
http_parse_error
:
public
error
server_http_1
()
{
{
max_content_length
=
10
*
1024
*
1024
;
// 10MB
public
:
}
http_parse_error
(
const
std
::
string
&
str
,
int
http_error_code_
)
:
error
(
str
),
http_error_code
(
http_error_code_
)
{}
unsigned
long
get_max_content_length
(
const
int
http_error_code
;
)
const
{
return
max_content_length
;
}
};
void
set_max_content_length
(
// ----------------------------------------------------------------------------------------
unsigned
long
max_length
)
{
max_content_length
=
max_length
;
}
template
<
typename
Key
,
typename
Value
>
template
<
typename
Key
,
typename
Value
>
class
constmap
:
public
std
::
map
<
Key
,
Value
>
class
constmap
:
public
std
::
map
<
Key
,
Value
>
...
@@ -78,10 +62,20 @@ namespace dlib
...
@@ -78,10 +62,20 @@ namespace dlib
typedef
constmap
<
std
::
string
,
std
::
string
>
key_value_map
;
typedef
constmap
<
std
::
string
,
std
::
string
>
key_value_map
;
struct
incoming_things
struct
incoming_things
{
{
incoming_things
()
:
foreign_port
(
0
),
local_port
(
0
)
{}
incoming_things
(
const
std
::
string
&
foreign_ip_
,
const
std
::
string
&
local_ip_
,
unsigned
short
foreign_port_
,
unsigned
short
local_port_
)
:
foreign_ip
(
foreign_ip_
),
foreign_port
(
foreign_port_
),
local_ip
(
local_ip_
),
local_port
(
local_port_
)
{}
std
::
string
path
;
std
::
string
path
;
std
::
string
request_type
;
std
::
string
request_type
;
...
@@ -101,7 +95,7 @@ namespace dlib
...
@@ -101,7 +95,7 @@ namespace dlib
struct
outgoing_things
struct
outgoing_things
{
{
outgoing_things
()
:
http_return
(
200
)
{
}
outgoing_things
()
:
http_return
(
200
),
http_return_status
(
"OK"
)
{
}
key_value_map
cookies
;
key_value_map
cookies
;
key_value_map
headers
;
key_value_map
headers
;
...
@@ -109,19 +103,16 @@ namespace dlib
...
@@ -109,19 +103,16 @@ namespace dlib
std
::
string
http_return_status
;
std
::
string
http_return_status
;
};
};
// ----------------------------------------------------------------------------------------
private
:
namespace
http_impl
virtual
const
std
::
string
on_request
(
{
const
incoming_things
&
incoming
,
inline
unsigned
char
to_hex
(
unsigned
char
x
)
outgoing_things
&
outgoing
)
=
0
;
unsigned
char
to_hex
(
unsigned
char
x
)
const
{
{
return
x
+
(
x
>
9
?
(
'A'
-
10
)
:
'0'
);
return
x
+
(
x
>
9
?
(
'A'
-
10
)
:
'0'
);
}
}
const
std
::
string
urlencode
(
const
std
::
string
&
s
)
const
inline
const
std
::
string
urlencode
(
const
std
::
string
&
s
)
{
{
std
::
ostringstream
os
;
std
::
ostringstream
os
;
...
@@ -146,9 +137,9 @@ namespace dlib
...
@@ -146,9 +137,9 @@ namespace dlib
return
os
.
str
();
return
os
.
str
();
}
}
unsigned
char
from_hex
(
inline
unsigned
char
from_hex
(
unsigned
char
ch
unsigned
char
ch
)
const
)
{
{
if
(
ch
<=
'9'
&&
ch
>=
'0'
)
if
(
ch
<=
'9'
&&
ch
>=
'0'
)
ch
-=
'0'
;
ch
-=
'0'
;
...
@@ -161,9 +152,9 @@ namespace dlib
...
@@ -161,9 +152,9 @@ namespace dlib
return
ch
;
return
ch
;
}
}
const
std
::
string
urldecode
(
inline
const
std
::
string
urldecode
(
const
std
::
string
&
str
const
std
::
string
&
str
)
const
)
{
{
using
namespace
std
;
using
namespace
std
;
string
result
;
string
result
;
...
@@ -190,7 +181,10 @@ namespace dlib
...
@@ -190,7 +181,10 @@ namespace dlib
return
result
;
return
result
;
}
}
void
parse_url
(
std
::
string
word
,
key_value_map
&
queries
)
inline
void
parse_url
(
std
::
string
word
,
key_value_map
&
queries
)
/*!
/*!
Parses the query string of a URL. word should be the stuff that comes
Parses the query string of a URL. word should be the stuff that comes
after the ? in the query URL.
after the ? in the query URL.
...
@@ -220,11 +214,11 @@ namespace dlib
...
@@ -220,11 +214,11 @@ namespace dlib
}
}
}
}
void
read_with_limit
(
inline
void
read_with_limit
(
std
::
istream
&
in
,
std
::
istream
&
in
,
std
::
string
&
buffer
,
std
::
string
&
buffer
,
int
delim
=
'\n'
int
delim
=
'\n'
)
const
)
{
{
using
namespace
std
;
using
namespace
std
;
const
size_t
max
=
16
*
1024
;
const
size_t
max
=
16
*
1024
;
...
@@ -236,6 +230,10 @@ namespace dlib
...
@@ -236,6 +230,10 @@ namespace dlib
buffer
+=
(
char
)
in
.
get
();
buffer
+=
(
char
)
in
.
get
();
}
}
// if we quit the loop because the data is longer than expected or we hit EOF
if
(
in
.
peek
()
==
EOF
||
buffer
.
size
()
==
max
)
throw
http_parse_error
(
"HTTP field from client is too long"
,
414
);
// Make sure the last char is the delim.
// Make sure the last char is the delim.
if
(
in
.
get
()
!=
delim
)
if
(
in
.
get
()
!=
delim
)
{
{
...
@@ -252,31 +250,17 @@ namespace dlib
...
@@ -252,31 +250,17 @@ namespace dlib
}
}
}
}
}
}
}
void
on_connect
(
inline
unsigned
long
parse_http_request
(
std
::
istream
&
in
,
std
::
istream
&
in
,
std
::
ostream
&
out
,
incoming_things
&
incoming
,
const
std
::
string
&
foreign_ip
,
unsigned
long
max_content_length
const
std
::
string
&
local_ip
,
unsigned
short
foreign_port
,
unsigned
short
local_port
,
uint64
)
)
{
{
bool
my_fault
=
true
;
using
namespace
std
;
using
namespace
std
;
using
namespace
http_impl
;
try
{
incoming_things
incoming
;
outgoing_things
outgoing
;
incoming
.
foreign_ip
=
foreign_ip
;
incoming
.
foreign_port
=
foreign_port
;
incoming
.
local_ip
=
local_ip
;
incoming
.
local_port
=
local_port
;
read_with_limit
(
in
,
incoming
.
request_type
,
' '
);
read_with_limit
(
in
,
incoming
.
request_type
,
' '
);
// get the path
// get the path
...
@@ -320,7 +304,16 @@ namespace dlib
...
@@ -320,7 +304,16 @@ namespace dlib
istringstream
sin
(
line
.
substr
(
16
));
istringstream
sin
(
line
.
substr
(
16
));
sin
>>
content_length
;
sin
>>
content_length
;
if
(
!
sin
)
if
(
!
sin
)
content_length
=
0
;
{
throw
http_parse_error
(
"Invalid Content-Length of '"
+
line
.
substr
(
16
)
+
"'"
,
411
);
}
if
(
content_length
>
max_content_length
)
{
std
::
ostringstream
sout
;
sout
<<
"Content-Length of post back is too large. It must be less than "
<<
max_content_length
;
throw
http_parse_error
(
sout
.
str
(),
413
);
}
}
}
// look for any cookies
// look for any cookies
else
if
(
line
.
size
()
>
6
&&
strings_equal_ignore_case
(
line
,
"Cookie:"
,
7
))
else
if
(
line
.
size
()
>
6
&&
strings_equal_ignore_case
(
line
,
"Cookie:"
,
7
))
...
@@ -375,18 +368,6 @@ namespace dlib
...
@@ -375,18 +368,6 @@ namespace dlib
read_with_limit
(
in
,
line
);
read_with_limit
(
in
,
line
);
}
// while (line.size() > 2 )
}
// while (line.size() > 2 )
// If there is data being posted back to us then load it into the incoming.body
// string.
if
(
content_length
>
max_content_length
)
{
dlog
<<
LERROR
<<
"Request from: "
<<
foreign_ip
<<
" - body content length "
<<
content_length
<<
" exceeded max content length of "
<<
max_content_length
;
in
.
setstate
(
ios
::
badbit
);
}
else
if
(
content_length
>
0
)
{
incoming
.
body
.
resize
(
content_length
);
in
.
read
(
&
incoming
.
body
[
0
],
content_length
);
}
// If there is data being posted back to us as a query string then
// If there is data being posted back to us as a query string then
// pick out the queries using parse_url.
// pick out the queries using parse_url.
...
@@ -394,6 +375,11 @@ namespace dlib
...
@@ -394,6 +375,11 @@ namespace dlib
strings_equal_ignore_case
(
incoming
.
request_type
,
"PUT"
))
&&
strings_equal_ignore_case
(
incoming
.
request_type
,
"PUT"
))
&&
strings_equal_ignore_case
(
left_substr
(
content_type
,
";"
),
"application/x-www-form-urlencoded"
))
strings_equal_ignore_case
(
left_substr
(
content_type
,
";"
),
"application/x-www-form-urlencoded"
))
{
{
if
(
content_length
>
0
)
{
incoming
.
body
.
resize
(
content_length
);
in
.
read
(
&
incoming
.
body
[
0
],
content_length
);
}
parse_url
(
incoming
.
body
,
incoming
.
queries
);
parse_url
(
incoming
.
body
,
incoming
.
queries
);
}
}
...
@@ -404,32 +390,43 @@ namespace dlib
...
@@ -404,32 +390,43 @@ namespace dlib
}
}
my_fault
=
false
;
if
(
!
in
)
key_value_map
&
new_cookies
=
outgoing
.
cookies
;
throw
http_parse_error
(
"Error parsing HTTP request"
,
500
);
key_value_map
&
response_headers
=
outgoing
.
headers
;
// Set some defaults
return
content_length
;
outgoing
.
http_return
=
200
;
}
outgoing
.
http_return_status
=
"OK"
;
// if there wasn't a problem with the input stream at some point
inline
void
read_body
(
// then lets trigger this request callback.
std
::
istream
&
in
,
std
::
string
result
;
incoming_things
&
incoming
if
(
in
)
)
{
{
result
=
on_request
(
incoming
,
outgoing
);
// if the body hasn't already been loaded and there is data to load
}
if
(
incoming
.
body
.
size
()
==
0
&&
else
incoming
.
headers
.
count
(
"Content-Length"
)
!=
0
)
{
const
unsigned
long
content_length
=
string_cast
<
unsigned
long
>
(
incoming
.
headers
[
"Content-Length"
]);
incoming
.
body
.
resize
(
content_length
);
if
(
content_length
>
0
)
{
{
dlog
<<
LERROR
<<
"Request from: "
<<
foreign_ip
<<
" - Invalid request - Request Entity Too Large"
;
in
.
read
(
&
incoming
.
body
[
0
],
content_length
)
;
outgoing
.
http_return
=
413
;
}
outgoing
.
http_return_status
=
"Request Entity Too Large"
;
}
}
}
my_fault
=
true
;
inline
void
write_http_response
(
std
::
ostream
&
out
,
outgoing_things
outgoing
,
const
std
::
string
&
result
)
{
using
namespace
http_impl
;
key_value_map
&
new_cookies
=
outgoing
.
cookies
;
key_value_map
&
response_headers
=
outgoing
.
headers
;
// only send this header if the user hasn't told us to send another kind
// only send this header if the user hasn't told us to send another kind
bool
has_content_type
(
false
),
bool
has_content_type
=
false
,
has_location
=
false
;
has_location
(
false
);
for
(
typename
key_value_map
::
const_iterator
ci
=
response_headers
.
begin
();
ci
!=
response_headers
.
end
();
++
ci
)
for
(
typename
key_value_map
::
const_iterator
ci
=
response_headers
.
begin
();
ci
!=
response_headers
.
end
();
++
ci
)
{
{
if
(
!
has_content_type
&&
strings_equal_ignore_case
(
ci
->
first
,
"content-type"
)
)
if
(
!
has_content_type
&&
strings_equal_ignore_case
(
ci
->
first
,
"content-type"
)
)
...
@@ -452,12 +449,7 @@ namespace dlib
...
@@ -452,12 +449,7 @@ namespace dlib
response_headers
[
"Content-Type"
]
=
"text/html"
;
response_headers
[
"Content-Type"
]
=
"text/html"
;
}
}
{
response_headers
[
"Content-Length"
]
=
cast_to_string
(
result
.
size
());
ostringstream
os
;
os
<<
result
.
size
();
response_headers
[
"Content-Length"
]
=
os
.
str
();
}
out
<<
"HTTP/1.0 "
<<
outgoing
.
http_return
<<
" "
<<
outgoing
.
http_return_status
<<
"
\r\n
"
;
out
<<
"HTTP/1.0 "
<<
outgoing
.
http_return
<<
" "
<<
outgoing
.
http_return_status
<<
"
\r\n
"
;
...
@@ -474,16 +466,98 @@ namespace dlib
...
@@ -474,16 +466,98 @@ namespace dlib
}
}
out
<<
"
\r\n
"
<<
result
;
out
<<
"
\r\n
"
<<
result
;
}
}
catch
(
std
::
bad_alloc
&
)
inline
void
write_http_response
(
std
::
ostream
&
out
,
const
http_parse_error
&
e
)
{
outgoing_things
outgoing
;
outgoing
.
http_return
=
e
.
http_error_code
;
outgoing
.
http_return_status
=
e
.
what
();
write_http_response
(
out
,
outgoing
,
std
::
string
(
"Error processing request: "
)
+
e
.
what
());
}
inline
void
write_http_response
(
std
::
ostream
&
out
,
const
std
::
exception
&
e
)
{
{
dlog
<<
LERROR
<<
"We ran out of memory in server_http::on_connect()"
;
outgoing_things
outgoing
;
// If this is an escaped exception from on_request then let it fly!
outgoing
.
http_return
=
500
;
// Seriously though, this way it is obvious to the user that something bad happened
outgoing
.
http_return_status
=
e
.
what
();
// since they probably won't have the dlib logger enabled.
write_http_response
(
out
,
outgoing
,
std
::
string
(
"Error processing request: "
)
+
e
.
what
());
if
(
!
my_fault
)
throw
;
}
}
// ----------------------------------------------------------------------------------------
template
<
typename
server_base
>
class
server_http_1
:
public
server_base
{
/*!
CONVENTION
this extension doesn't add any new state to this object.
!*/
public
:
server_http_1
()
{
max_content_length
=
10
*
1024
*
1024
;
// 10MB
}
unsigned
long
get_max_content_length
(
)
const
{
return
max_content_length
;
}
void
set_max_content_length
(
unsigned
long
max_length
)
{
max_content_length
=
max_length
;
}
private
:
virtual
const
std
::
string
on_request
(
const
incoming_things
&
incoming
,
outgoing_things
&
outgoing
)
=
0
;
void
on_connect
(
std
::
istream
&
in
,
std
::
ostream
&
out
,
const
std
::
string
&
foreign_ip
,
const
std
::
string
&
local_ip
,
unsigned
short
foreign_port
,
unsigned
short
local_port
,
uint64
)
{
try
{
incoming_things
incoming
(
foreign_ip
,
local_ip
,
foreign_port
,
local_port
);
outgoing_things
outgoing
;
parse_http_request
(
in
,
incoming
,
max_content_length
);
read_body
(
in
,
incoming
);
const
std
::
string
&
result
=
on_request
(
incoming
,
outgoing
);
write_http_response
(
out
,
outgoing
,
result
);
}
catch
(
http_parse_error
&
e
)
{
dlog
<<
LERROR
<<
"Error processing request from: "
<<
foreign_ip
<<
" - "
<<
e
.
what
();
write_http_response
(
out
,
e
);
}
catch
(
std
::
exception
&
e
)
{
dlog
<<
LERROR
<<
"Error processing request from: "
<<
foreign_ip
<<
" - "
<<
e
.
what
();
write_http_response
(
out
,
e
);
}
}
}
unsigned
long
max_content_length
;
unsigned
long
max_content_length
;
...
@@ -498,6 +572,3 @@ namespace dlib
...
@@ -498,6 +572,3 @@ namespace dlib
#endif // DLIB_SERVER_HTTp_1_
#endif // DLIB_SERVER_HTTp_1_
dlib/server/server_http_abstract.h
View file @
1db057d6
...
@@ -193,7 +193,8 @@ namespace dlib
...
@@ -193,7 +193,8 @@ namespace dlib
- outgoing.http_return and outgoing.http_return_status may be set to override the
- outgoing.http_return and outgoing.http_return_status may be set to override the
default HTTP return code of 200 OK
default HTTP return code of 200 OK
throws
throws
- does not throw any exceptions
- throws only exceptions derived from std::exception. If an exception is thrown
then the error string from the exception is returned to the web browser.
!*/
!*/
};
};
...
...
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