Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
dlib
Commits
1db057d6
Commit
1db057d6
authored
Nov 07, 2012
by
Davis King
Browse files
Refactored the code in the http server so that it will be more reusable
by other tools.
parent
05b1ba8b
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
356 additions
and
284 deletions
+356
-284
dlib/server/server_http_1.h
dlib/server/server_http_1.h
+354
-283
dlib/server/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 @@
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:
server_http_1
()
class
http_parse_error
:
public
error
{
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
{
return
max_content_length
;
}
const
int
http_error_code
;
}
;
void
set_max_content_length
(
unsigned
long
max_length
)
{
max_content_length
=
max_length
;
}
// ----------------------------------------------------------------------------------------
template
<
typename
Key
,
typename
Value
>
class
constmap
:
public
std
::
map
<
Key
,
Value
>
...
...
@@ -78,10 +62,20 @@ namespace dlib
typedef
constmap
<
std
::
string
,
std
::
string
>
key_value_map
;
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
request_type
;
...
...
@@ -101,7 +95,7 @@ namespace dlib
struct
outgoing_things
{
outgoing_things
()
:
http_return
(
200
)
{
}
outgoing_things
()
:
http_return
(
200
)
,
http_return_status
(
"OK"
)
{
}
key_value_map
cookies
;
key_value_map
headers
;
...
...
@@ -109,19 +103,16 @@ namespace dlib
std
::
string
http_return_status
;
};
// ----------------------------------------------------------------------------------------
private:
virtual
const
std
::
string
on_request
(
const
incoming_things
&
incoming
,
outgoing_things
&
outgoing
)
=
0
;
unsigned
char
to_hex
(
unsigned
char
x
)
const
namespace
http_impl
{
inline
unsigned
char
to_hex
(
unsigned
char
x
)
{
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
;
...
...
@@ -146,9 +137,9 @@ namespace dlib
return
os
.
str
();
}
unsigned
char
from_hex
(
inline
unsigned
char
from_hex
(
unsigned
char
ch
)
const
)
{
if
(
ch
<=
'9'
&&
ch
>=
'0'
)
ch
-=
'0'
;
...
...
@@ -161,9 +152,9 @@ namespace dlib
return
ch
;
}
const
std
::
string
urldecode
(
inline
const
std
::
string
urldecode
(
const
std
::
string
&
str
)
const
)
{
using
namespace
std
;
string
result
;
...
...
@@ -190,7 +181,10 @@ namespace dlib
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
after the ? in the query URL.
...
...
@@ -220,11 +214,11 @@ namespace dlib
}
}
void
read_with_limit
(
inline
void
read_with_limit
(
std
::
istream
&
in
,
std
::
string
&
buffer
,
int
delim
=
'\n'
)
const
)
{
using
namespace
std
;
const
size_t
max
=
16
*
1024
;
...
...
@@ -236,6 +230,10 @@ namespace dlib
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.
if
(
in
.
get
()
!=
delim
)
{
...
...
@@ -252,31 +250,17 @@ namespace dlib
}
}
}
}
void
on_connect
(
inline
unsigned
long
parse_http_request
(
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
incoming_things
&
incoming
,
unsigned
long
max_content_length
)
{
bool
my_fault
=
true
;
using
namespace
std
;
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
;
using
namespace
http_impl
;
read_with_limit
(
in
,
incoming
.
request_type
,
' '
);
// get the path
...
...
@@ -320,7 +304,16 @@ namespace dlib
istringstream
sin
(
line
.
substr
(
16
));
sin
>>
content_length
;
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
else
if
(
line
.
size
()
>
6
&&
strings_equal_ignore_case
(
line
,
"Cookie:"
,
7
))
...
...
@@ -375,18 +368,6 @@ namespace dlib
read_with_limit
(
in
,
line
);
}
// 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
// pick out the queries using parse_url.
...
...
@@ -394,6 +375,11 @@ namespace dlib
strings_equal_ignore_case
(
incoming
.
request_type
,
"PUT"
))
&&
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
);
}
...
...
@@ -404,32 +390,43 @@ namespace dlib
}
my_fault
=
false
;
key_value_map
&
new_cookies
=
outgoing
.
cookies
;
key_value_map
&
response_headers
=
outgoing
.
headers
;
if
(
!
in
)
throw
http_parse_error
(
"Error parsing HTTP request"
,
500
);
// Set some defaults
outgoing
.
http_return
=
200
;
outgoing
.
http_return_status
=
"OK"
;
return
content_length
;
}
// if there wasn't a problem with the input stream at some point
// then lets trigger th
is
re
quest callback.
std
::
string
result
;
if
(
in
)
inline
void
read_body
(
std
::
is
t
re
am
&
in
,
incoming_things
&
incoming
)
{
result
=
on_request
(
incoming
,
outgoing
);
}
else
// if the body hasn't already been loaded and there is data to load
if
(
incoming
.
body
.
size
()
==
0
&&
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"
;
outgoing
.
http_return
=
413
;
outgoing
.
http_return_status
=
"Request Entity Too Large"
;
in
.
read
(
&
incoming
.
body
[
0
],
content_length
)
;
}
}
}
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
bool
has_content_type
(
false
),
has_location
(
false
);
bool
has_content_type
=
false
,
has_location
=
false
;
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"
)
)
...
...
@@ -452,12 +449,7 @@ namespace dlib
response_headers
[
"Content-Type"
]
=
"text/html"
;
}
{
ostringstream
os
;
os
<<
result
.
size
();
response_headers
[
"Content-Length"
]
=
os
.
str
();
}
response_headers
[
"Content-Length"
]
=
cast_to_string
(
result
.
size
());
out
<<
"HTTP/1.0 "
<<
outgoing
.
http_return
<<
" "
<<
outgoing
.
http_return_status
<<
"
\r\n
"
;
...
...
@@ -474,16 +466,98 @@ namespace dlib
}
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()"
;
// If this is an escaped exception from on_request then let it fly!
// Seriously though, this way it is obvious to the user that something bad happened
// since they probably won't have the dlib logger enabled.
if
(
!
my_fault
)
throw
;
outgoing_things
outgoing
;
outgoing
.
http_return
=
500
;
outgoing
.
http_return_status
=
e
.
what
();
write_http_response
(
out
,
outgoing
,
std
::
string
(
"Error processing request: "
)
+
e
.
what
());
}
// ----------------------------------------------------------------------------------------
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
;
...
...
@@ -498,6 +572,3 @@ namespace dlib
#endif // DLIB_SERVER_HTTp_1_
dlib/server/server_http_abstract.h
View file @
1db057d6
...
...
@@ -193,7 +193,8 @@ namespace dlib
- outgoing.http_return and outgoing.http_return_status may be set to override the
default HTTP return code of 200 OK
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