Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pistache
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
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
Libraries
pistache
Commits
b63025ad
Commit
b63025ad
authored
Sep 01, 2015
by
Mathieu Stefani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved some definitions inside an independent http_defs header. Also implemented some more headers
parent
8e503d63
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
637 additions
and
179 deletions
+637
-179
src/CMakeLists.txt
src/CMakeLists.txt
+1
-0
src/http.cc
src/http.cc
+0
-36
src/http.h
src/http.h
+1
-89
src/http_defs.cc
src/http_defs.cc
+109
-0
src/http_defs.h
src/http_defs.h
+136
-0
src/http_header.cc
src/http_header.cc
+181
-0
src/http_header.h
src/http_header.h
+109
-54
tests/headers_test.cc
tests/headers_test.cc
+100
-0
No files found.
src/CMakeLists.txt
View file @
b63025ad
...
...
@@ -7,6 +7,7 @@ set(SOURCE_FILES
http.cc
http_header.cc
http_headers.cc
http_defs.cc
mime.cc
)
...
...
src/http.cc
View file @
b63025ad
...
...
@@ -339,42 +339,6 @@ namespace Private {
}
// namespace Private
const
char
*
methodString
(
Method
method
)
{
switch
(
method
)
{
#define METHOD(name, str) \
case Method::name: \
return str;
HTTP_METHODS
#undef METHOD
}
unreachable
();
}
const
char
*
codeString
(
Code
code
)
{
switch
(
code
)
{
#define CODE(_, name, str) \
case Code::name: \
return str;
STATUS_CODES
#undef CODE
}
return
""
;
}
HttpError
::
HttpError
(
Code
code
,
std
::
string
reason
)
:
code_
(
static_cast
<
int
>
(
code
))
,
reason_
(
std
::
move
(
reason
))
{
}
HttpError
::
HttpError
(
int
code
,
std
::
string
reason
)
:
code_
(
code
)
,
reason_
(
std
::
move
(
reason
))
{
}
Message
::
Message
()
:
version
(
Version
::
Http11
)
{
}
...
...
src/http.h
View file @
b63025ad
...
...
@@ -12,100 +12,12 @@
#include "listener.h"
#include "net.h"
#include "http_headers.h"
#include "http_defs.h"
namespace
Net
{
namespace
Http
{
#define HTTP_METHODS \
METHOD(Options, "OPTIONS") \
METHOD(Get, "GET") \
METHOD(Post, "POST") \
METHOD(Head, "HEAD") \
METHOD(Put, "PUT") \
METHOD(Delete, "DELETE") \
METHOD(Trace, "TRACE") \
METHOD(Connect, "CONNECT")
// 10. Status Code Definitions
#define STATUS_CODES \
CODE(100, Continue, "Continue") \
CODE(101, Switching_Protocols, "Switching Protocols") \
CODE(200, Ok, "OK") \
CODE(201, Created, "Created") \
CODE(202, Accepted, "Accepted") \
CODE(203, NonAuthoritative_Information, "Non-Authoritative Information") \
CODE(204, No_Content, "No Content") \
CODE(205, Reset_Content, "Reset Content") \
CODE(206, Partial_Content, "Partial Content") \
CODE(300, Multiple_Choices, "Multiple Choices") \
CODE(301, Moved_Permanently, "Moved Permanently") \
CODE(302, Found, "Found") \
CODE(303, See_Other, "See Other") \
CODE(304, Not_Modified, "Not Modified") \
CODE(305, Use_Proxy, "Use Proxy") \
CODE(307, Temporary_Redirect, "Temporary Redirect") \
CODE(400, Bad_Request, "Bad Request") \
CODE(401, Unauthorized, "Unauthorized") \
CODE(402, Payment_Required, "Payment Required") \
CODE(403, Forbidden, "Forbidden") \
CODE(404, Not_Found, "Not Found") \
CODE(405, Method_Not_Allowed, "Method Not Allowed") \
CODE(406, Not_Acceptable, "Not Acceptable") \
CODE(407, Proxy_Authentication_Required, "Proxy Authentication Required") \
CODE(408, Request_Timeout, "Request Timeout") \
CODE(409, Conflict, "Conflict") \
CODE(410, Gone, "Gone") \
CODE(411, Length_Required, "Length Required") \
CODE(412, Precondition_Failed, "Precondition Failed") \
CODE(413, Request_Entity_Too_Large, "Request Entity Too Large") \
CODE(414, RequestURI_Too_Long, "Request-URI Too Long") \
CODE(415, Unsupported_Media_Type, "Unsupported Media Type") \
CODE(416, Requested_Range_Not_Satisfiable, "Requested Range Not Satisfiable") \
CODE(417, Expectation_Failed, "Expectation Failed") \
CODE(500, Internal_Server_Error, "Internal Server Error") \
CODE(501, Not_Implemented, "Not Implemented") \
CODE(502, Bad_Gateway, "Bad Gateway") \
CODE(503, Service_Unavailable, "Service Unavailable") \
CODE(504, Gateway_Timeout, "Gateway Timeout")
enum
class
Method
{
#define METHOD(m, _) m,
HTTP_METHODS
#undef METHOD
};
enum
class
Code
{
#define CODE(value, name, _) name = value,
STATUS_CODES
#undef CODE
};
enum
class
Version
{
Http10
,
// HTTP/1.0
Http11
// HTTP/1.1
};
const
char
*
methodString
(
Method
method
);
const
char
*
codeString
(
Code
code
);
struct
HttpError
:
public
std
::
exception
{
HttpError
(
Code
code
,
std
::
string
reason
);
HttpError
(
int
code
,
std
::
string
reason
);
~
HttpError
()
noexcept
{
}
const
char
*
what
()
const
noexcept
{
return
reason_
.
c_str
();
}
int
code
()
const
{
return
code_
;
}
std
::
string
reason
()
const
{
return
reason_
;
}
private:
int
code_
;
std
::
string
reason_
;
};
// 4. HTTP Message
class
Message
{
public:
...
...
src/http_defs.cc
0 → 100644
View file @
b63025ad
/* http_defs.cc
Mathieu Stefani, 01 September 2015
Implementation of http definitions
*/
#include "http_defs.h"
#include "common.h"
namespace
Net
{
namespace
Http
{
CacheDirective
::
CacheDirective
(
Directive
directive
)
{
init
(
directive
,
std
::
chrono
::
seconds
(
0
));
}
CacheDirective
::
CacheDirective
(
Directive
directive
,
std
::
chrono
::
seconds
delta
)
{
init
(
directive
,
delta
);
}
std
::
chrono
::
seconds
CacheDirective
::
delta
()
const
{
switch
(
directive_
)
{
case
MaxAge
:
return
std
::
chrono
::
seconds
(
data
.
maxAge
);
case
SMaxAge
:
return
std
::
chrono
::
seconds
(
data
.
sMaxAge
);
case
MaxStale
:
return
std
::
chrono
::
seconds
(
data
.
maxStale
);
case
MinFresh
:
return
std
::
chrono
::
seconds
(
data
.
minFresh
);
}
throw
std
::
domain_error
(
"Invalid operation on cache directive"
);
}
void
CacheDirective
::
init
(
Directive
directive
,
std
::
chrono
::
seconds
delta
)
{
directive_
=
directive
;
switch
(
directive
)
{
case
MaxAge
:
data
.
maxAge
=
delta
.
count
();
break
;
case
SMaxAge
:
data
.
sMaxAge
=
delta
.
count
();
break
;
case
MaxStale
:
data
.
maxStale
=
delta
.
count
();
break
;
case
MinFresh
:
data
.
minFresh
=
delta
.
count
();
break
;
}
}
const
char
*
methodString
(
Method
method
)
{
switch
(
method
)
{
#define METHOD(name, str) \
case Method::name: \
return str;
HTTP_METHODS
#undef METHOD
}
unreachable
();
}
const
char
*
codeString
(
Code
code
)
{
switch
(
code
)
{
#define CODE(_, name, str) \
case Code::name: \
return str;
STATUS_CODES
#undef CODE
}
return
""
;
}
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
Method
method
)
{
os
<<
methodString
(
method
);
return
os
;
}
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
Code
code
)
{
os
<<
codeString
(
code
);
}
HttpError
::
HttpError
(
Code
code
,
std
::
string
reason
)
:
code_
(
static_cast
<
int
>
(
code
))
,
reason_
(
std
::
move
(
reason
))
{
}
HttpError
::
HttpError
(
int
code
,
std
::
string
reason
)
:
code_
(
code
)
,
reason_
(
std
::
move
(
reason
))
{
}
}
// namespace Http
}
// namespace Net
src/http_defs.h
0 → 100644
View file @
b63025ad
/* http_defs.h
Mathieu Stefani, 01 September 2015
Various http definitions
*/
#pragma once
#include <string>
#include <ostream>
#include <stdexcept>
#include <chrono>
namespace
Net
{
namespace
Http
{
#define HTTP_METHODS \
METHOD(Options, "OPTIONS") \
METHOD(Get, "GET") \
METHOD(Post, "POST") \
METHOD(Head, "HEAD") \
METHOD(Put, "PUT") \
METHOD(Delete, "DELETE") \
METHOD(Trace, "TRACE") \
METHOD(Connect, "CONNECT")
// 10. Status Code Definitions
#define STATUS_CODES \
CODE(100, Continue, "Continue") \
CODE(101, Switching_Protocols, "Switching Protocols") \
CODE(200, Ok, "OK") \
CODE(201, Created, "Created") \
CODE(202, Accepted, "Accepted") \
CODE(203, NonAuthoritative_Information, "Non-Authoritative Information") \
CODE(204, No_Content, "No Content") \
CODE(205, Reset_Content, "Reset Content") \
CODE(206, Partial_Content, "Partial Content") \
CODE(300, Multiple_Choices, "Multiple Choices") \
CODE(301, Moved_Permanently, "Moved Permanently") \
CODE(302, Found, "Found") \
CODE(303, See_Other, "See Other") \
CODE(304, Not_Modified, "Not Modified") \
CODE(305, Use_Proxy, "Use Proxy") \
CODE(307, Temporary_Redirect, "Temporary Redirect") \
CODE(400, Bad_Request, "Bad Request") \
CODE(401, Unauthorized, "Unauthorized") \
CODE(402, Payment_Required, "Payment Required") \
CODE(403, Forbidden, "Forbidden") \
CODE(404, Not_Found, "Not Found") \
CODE(405, Method_Not_Allowed, "Method Not Allowed") \
CODE(406, Not_Acceptable, "Not Acceptable") \
CODE(407, Proxy_Authentication_Required, "Proxy Authentication Required") \
CODE(408, Request_Timeout, "Request Timeout") \
CODE(409, Conflict, "Conflict") \
CODE(410, Gone, "Gone") \
CODE(411, Length_Required, "Length Required") \
CODE(412, Precondition_Failed, "Precondition Failed") \
CODE(413, Request_Entity_Too_Large, "Request Entity Too Large") \
CODE(414, RequestURI_Too_Long, "Request-URI Too Long") \
CODE(415, Unsupported_Media_Type, "Unsupported Media Type") \
CODE(416, Requested_Range_Not_Satisfiable, "Requested Range Not Satisfiable") \
CODE(417, Expectation_Failed, "Expectation Failed") \
CODE(500, Internal_Server_Error, "Internal Server Error") \
CODE(501, Not_Implemented, "Not Implemented") \
CODE(502, Bad_Gateway, "Bad Gateway") \
CODE(503, Service_Unavailable, "Service Unavailable") \
CODE(504, Gateway_Timeout, "Gateway Timeout")
enum
class
Method
{
#define METHOD(m, _) m,
HTTP_METHODS
#undef METHOD
};
enum
class
Code
{
#define CODE(value, name, _) name = value,
STATUS_CODES
#undef CODE
};
enum
class
Version
{
Http10
,
// HTTP/1.0
Http11
// HTTP/1.1
};
class
CacheDirective
{
public:
enum
Directive
{
NoCache
,
NoStore
,
MaxAge
,
MaxStale
,
MinFresh
,
NoTransform
,
OnlyIfCached
,
Public
,
Private
,
MustRevalidate
,
ProxyRevalidate
,
SMaxAge
,
Ext
};
CacheDirective
()
{
}
CacheDirective
(
Directive
directive
);
CacheDirective
(
Directive
directive
,
std
::
chrono
::
seconds
delta
);
Directive
directive
()
const
{
return
directive_
;
}
std
::
chrono
::
seconds
delta
()
const
;
private:
void
init
(
Directive
directive
,
std
::
chrono
::
seconds
delta
);
Directive
directive_
;
// Poor way of representing tagged unions in C++
union
{
struct
{
uint64_t
maxAge
;
};
struct
{
uint64_t
sMaxAge
;
};
struct
{
uint64_t
maxStale
;
};
struct
{
uint64_t
minFresh
;
};
}
data
;
}
;
const
char
*
methodString
(
Method
method
);
const
char
*
codeString
(
Code
code
);
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
Method
method
);
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
Code
code
);
struct
HttpError
:
public
std
::
exception
{
HttpError
(
Code
code
,
std
::
string
reason
);
HttpError
(
int
code
,
std
::
string
reason
);
~
HttpError
()
noexcept
{
}
const
char
*
what
()
const
noexcept
{
return
reason_
.
c_str
();
}
int
code
()
const
{
return
code_
;
}
std
::
string
reason
()
const
{
return
reason_
;
}
private:
int
code_
;
std
::
string
reason_
;
};
}
// namespace Http
}
// namespace Net
src/http_header.cc
View file @
b63025ad
...
...
@@ -47,6 +47,187 @@ Header::parseRaw(const char *str, size_t len) {
parse
(
std
::
string
(
str
,
len
));
}
void
Allow
::
parseRaw
(
const
char
*
str
,
size_t
len
)
{
}
void
Allow
::
write
(
std
::
ostream
&
os
)
const
{
/* This puts an extra ',' at the end :/
std::copy(std::begin(methods_), std::end(methods_),
std::ostream_iterator<Http::Method>(os, ", "));
*/
for
(
std
::
vector
<
Http
::
Method
>::
size_type
i
=
0
;
i
<
methods_
.
size
();
++
i
)
{
os
<<
methods_
[
i
];
if
(
i
<
methods_
.
size
()
-
1
)
os
<<
", "
;
}
}
void
Allow
::
addMethod
(
Http
::
Method
method
)
{
methods_
.
push_back
(
method
);
}
void
Allow
::
addMethods
(
std
::
initializer_list
<
Method
>
methods
)
{
std
::
copy
(
std
::
begin
(
methods
),
std
::
end
(
methods
),
std
::
back_inserter
(
methods_
));
}
void
Allow
::
addMethods
(
const
std
::
vector
<
Http
::
Method
>&
methods
)
{
std
::
copy
(
std
::
begin
(
methods
),
std
::
end
(
methods
),
std
::
back_inserter
(
methods_
));
}
CacheControl
::
CacheControl
(
Http
::
CacheDirective
directive
)
{
directives_
.
push_back
(
directive
);
}
void
CacheControl
::
parseRaw
(
const
char
*
str
,
size_t
len
)
{
using
Http
::
CacheDirective
;
auto
eof
=
[
&
](
const
char
*
p
)
{
return
p
-
str
==
len
;
};
#define MAX_SIZE(s) \
std::min(sizeof(s) - 1, len - (begin - str))
#define TRY_PARSE_TRIVIAL_DIRECTIVE(dstr, directive) \
if (memcmp(begin, dstr, MAX_SIZE(dstr)) == 0) { \
directives_.push_back(CacheDirective(CacheDirective::directive)); \
begin += sizeof(dstr) - 1; \
break; \
} \
(void) 0
// @Todo: check for overflow
#define TRY_PARSE_TIMED_DIRECTIVE(dstr, directive) \
if (memcmp(begin, dstr, MAX_SIZE(dstr)) == 0) { \
const char *p = static_cast<const char *>(memchr(str, '=', len)); \
if (p == NULL) { \
throw std::runtime_error("Invalid caching directive, missing delta-seconds"); \
} \
char *end; \
int secs = strtol(p + 1, &end, 10); \
if (!eof(end) && *end != ',') { \
throw std::runtime_error("Invalid caching directive, malformated delta-seconds"); \
} \
directives_.push_back(CacheDirective(CacheDirective::directive, std::chrono::seconds(secs))); \
begin = end; \
break; \
} \
(void) 0
const
char
*
begin
=
str
;
do
{
do
{
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"no-cache"
,
NoCache
);
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"no-store"
,
NoStore
);
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"no-transform"
,
NoTransform
);
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"only-if-cached"
,
OnlyIfCached
);
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"public"
,
Public
);
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"private"
,
Private
);
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"must-revalidate"
,
MustRevalidate
);
TRY_PARSE_TRIVIAL_DIRECTIVE
(
"proxy-revalidate"
,
ProxyRevalidate
);
TRY_PARSE_TIMED_DIRECTIVE
(
"max-age"
,
MaxAge
);
TRY_PARSE_TIMED_DIRECTIVE
(
"max-stale"
,
MaxStale
);
TRY_PARSE_TIMED_DIRECTIVE
(
"min-fresh"
,
MinFresh
);
TRY_PARSE_TIMED_DIRECTIVE
(
"s-maxage"
,
SMaxAge
);
}
while
(
false
);
if
(
!
eof
(
begin
))
{
if
(
*
begin
!=
','
)
throw
std
::
runtime_error
(
"Invalid caching directive, expected a comma"
);
while
(
!
eof
(
begin
)
&&
*
begin
==
','
||
*
begin
==
' '
)
++
begin
;
}
}
while
(
!
eof
(
begin
));
#undef TRY_PARSE_TRIVIAL_DIRECTIVE
#undef TRY_PARSE_TIMED_DIRECTIVE
}
void
CacheControl
::
write
(
std
::
ostream
&
os
)
const
{
using
Http
::
CacheDirective
;
auto
directiveString
=
[](
CacheDirective
directive
)
->
const
char
*
const
{
switch
(
directive
.
directive
())
{
case
CacheDirective
:
:
NoCache
:
return
"no-cache"
;
case
CacheDirective
:
:
NoStore
:
return
"no-store"
;
case
CacheDirective
:
:
NoTransform
:
return
"no-transform"
;
case
CacheDirective
:
:
OnlyIfCached
:
return
"only-if-cached"
;
case
CacheDirective
:
:
Public
:
return
"public"
;
case
CacheDirective
:
:
Private
:
return
"private"
;
case
CacheDirective
:
:
MustRevalidate
:
return
"must-revalidate"
;
case
CacheDirective
:
:
ProxyRevalidate
:
return
"proxy-revalidate"
;
case
CacheDirective
:
:
MaxAge
:
return
"max-age"
;
case
CacheDirective
:
:
MaxStale
:
return
"max-stale"
;
case
CacheDirective
:
:
MinFresh
:
return
"min-fresh"
;
case
CacheDirective
:
:
SMaxAge
:
return
"s-maxage"
;
}
};
auto
hasDelta
=
[](
CacheDirective
directive
)
{
switch
(
directive
.
directive
())
{
case
CacheDirective
:
:
MaxAge
:
case
CacheDirective
:
:
MaxStale
:
case
CacheDirective
:
:
MinFresh
:
case
CacheDirective
:
:
SMaxAge
:
return
true
;
}
return
false
;
};
for
(
std
::
vector
<
CacheDirective
>::
size_type
i
=
0
;
i
<
directives_
.
size
();
++
i
)
{
const
auto
&
d
=
directives_
[
i
];
os
<<
directiveString
(
d
);
if
(
hasDelta
(
d
))
{
auto
delta
=
d
.
delta
();
if
(
delta
.
count
()
>
0
)
{
os
<<
"="
<<
delta
.
count
();
}
}
if
(
i
<
directives_
.
size
()
-
1
)
{
os
<<
", "
;
}
}
}
void
CacheControl
::
addDirective
(
Http
::
CacheDirective
directive
)
{
directives_
.
push_back
(
directive
);
}
void
CacheControl
::
addDirectives
(
const
std
::
vector
<
Http
::
CacheDirective
>&
directives
)
{
std
::
copy
(
std
::
begin
(
directives
),
std
::
end
(
directives
),
std
::
back_inserter
(
directives_
));
}
void
ContentLength
::
parse
(
const
std
::
string
&
data
)
{
try
{
...
...
src/http_header.h
View file @
b63025ad
...
...
@@ -8,6 +8,7 @@
#include "mime.h"
#include "net.h"
#include "http_defs.h"
#include <string>
#include <type_traits>
#include <memory>
...
...
@@ -111,104 +112,160 @@ header_cast(const std::shared_ptr<const Header>& from)
}
#endif
class
ContentLength
:
public
Header
{
class
Allow
:
public
Header
{
public:
NAME
(
"
Content-Length
"
);
NAME
(
"
Allow
"
);
ContentLength
()
:
value_
(
0
)
Allow
()
{
}
explicit
Allow
(
const
std
::
vector
<
Http
::
Method
>&
methods
)
:
methods_
(
methods
)
{
}
explicit
Allow
(
std
::
initializer_list
<
Http
::
Method
>
methods
)
:
methods_
(
methods
)
{
}
explicit
ContentLength
(
uint64_t
val
)
:
value_
(
val
)
explicit
Allow
(
Http
::
Method
method
)
{
methods_
.
push_back
(
method
);
}
void
parseRaw
(
const
char
*
str
,
size_t
len
);
void
write
(
std
::
ostream
&
os
)
const
;
void
addMethod
(
Http
::
Method
method
);
void
addMethods
(
std
::
initializer_list
<
Method
>
methods
);
void
addMethods
(
const
std
::
vector
<
Http
::
Method
>&
methods
);
std
::
vector
<
Http
::
Method
>
methods
()
const
{
return
methods_
;
}
private:
std
::
vector
<
Http
::
Method
>
methods_
;
};
class
Accept
:
public
Header
{
public:
NAME
(
"Accept"
)
Accept
()
{
}
void
parseRaw
(
const
char
*
str
,
size_t
len
);
void
write
(
std
::
ostream
&
os
)
const
;
const
std
::
vector
<
Mime
::
MediaType
>
media
()
const
{
return
mediaRange_
;
}
private:
std
::
vector
<
Mime
::
MediaType
>
mediaRange_
;
};
class
CacheControl
:
public
Header
{
public:
NAME
(
"Cache-Control"
)
CacheControl
()
{
}
explicit
CacheControl
(
const
std
::
vector
<
Http
::
CacheDirective
>&
directives
)
:
directives_
(
directives
)
{
}
explicit
CacheControl
(
Http
::
CacheDirective
directive
);
void
parse
(
const
std
::
string
&
data
);
void
parse
Raw
(
const
char
*
str
,
size_t
len
);
void
write
(
std
::
ostream
&
os
)
const
;
uint64_t
value
()
const
{
return
value_
;
}
std
::
vector
<
Http
::
CacheDirective
>
directives
()
const
{
return
directives_
;
}
void
addDirective
(
Http
::
CacheDirective
directive
);
void
addDirectives
(
const
std
::
vector
<
Http
::
CacheDirective
>&
directives
);
private:
uint64_t
value
_
;
std
::
vector
<
Http
::
CacheDirective
>
directives
_
;
};
class
Host
:
public
Header
{
class
ContentEncoding
:
public
Header
{
public:
NAME
(
"
Host"
);
NAME
(
"
Content-Encoding"
)
Host
()
:
host_
()
,
port_
(
-
1
)
ContentEncoding
()
:
encoding_
(
Encoding
::
Identity
)
{
}
explicit
Host
(
const
std
::
string
&
host
,
Net
::
Port
port
=
80
)
:
host_
(
host
)
,
port_
(
port
)
explicit
ContentEncoding
(
Encoding
encoding
)
:
encoding_
(
encoding
)
{
}
void
parse
(
const
std
::
string
&
data
);
void
parse
Raw
(
const
char
*
str
,
size_t
len
);
void
write
(
std
::
ostream
&
os
)
const
;
std
::
string
host
()
const
{
return
host_
;
}
Net
::
Port
port
()
const
{
return
port_
;
}
Encoding
encoding
()
const
{
return
encoding_
;
}
private:
std
::
string
host_
;
Net
::
Port
port_
;
Encoding
encoding_
;
};
class
UserAgent
:
public
Header
{
class
ContentLength
:
public
Header
{
public:
NAME
(
"
User-Agent"
)
NAME
(
"
Content-Length"
);
UserAgent
()
{
}
explicit
UserAgent
(
const
std
::
string
&
ua
)
:
ua_
(
ua
)
ContentLength
()
:
value_
(
0
)
{
}
explicit
ContentLength
(
uint64_t
val
)
:
value_
(
val
)
{
}
void
parse
(
const
std
::
string
&
data
);
void
write
(
std
::
ostream
&
os
)
const
;
std
::
string
ua
()
const
{
return
ua
_
;
}
uint64_t
value
()
const
{
return
value
_
;
}
private:
std
::
string
ua
_
;
uint64_t
value
_
;
};
class
Accept
:
public
Header
{
class
ContentType
:
public
Header
{
public:
NAME
(
"
Accept
"
)
NAME
(
"
Content-Type
"
)
Accept
()
{
}
ContentType
()
{
}
void
parseRaw
(
const
char
*
str
,
size_t
len
);
explicit
ContentType
(
const
Mime
::
MediaType
&
mime
)
:
mime_
(
mime
)
{
}
void
parseRaw
(
const
char
*
str
,
size_t
len
);
void
write
(
std
::
ostream
&
os
)
const
;
const
std
::
vector
<
Mime
::
MediaType
>
media
()
const
{
return
mediaRang
e_
;
}
Mime
::
MediaType
mime
()
const
{
return
mim
e_
;
}
private:
std
::
vector
<
Mime
::
MediaType
>
mediaRange_
;
Mime
::
MediaType
mime_
;
};
class
ContentEncoding
:
public
Header
{
class
Host
:
public
Header
{
public:
NAME
(
"
Content-Encoding"
)
NAME
(
"
Host"
);
ContentEncoding
()
:
encoding_
(
Encoding
::
Identity
)
Host
()
:
host_
()
,
port_
(
-
1
)
{
}
explicit
ContentEncoding
(
Encoding
encoding
)
:
encoding_
(
encoding
)
explicit
Host
(
const
std
::
string
&
host
,
Net
::
Port
port
=
80
)
:
host_
(
host
)
,
port_
(
port
)
{
}
void
parse
Raw
(
const
char
*
str
,
size_t
len
);
void
parse
(
const
std
::
string
&
data
);
void
write
(
std
::
ostream
&
os
)
const
;
Encoding
encoding
()
const
{
return
encoding_
;
}
std
::
string
host
()
const
{
return
host_
;
}
Net
::
Port
port
()
const
{
return
port_
;
}
private:
Encoding
encoding_
;
std
::
string
host_
;
Net
::
Port
port_
;
};
class
Server
:
public
Header
{
...
...
@@ -229,24 +286,22 @@ private:
std
::
vector
<
std
::
string
>
tokens_
;
};
class
ContentType
:
public
Header
{
class
UserAgent
:
public
Header
{
public:
NAME
(
"Content-Type"
)
ContentType
()
{
}
NAME
(
"User-Agent"
)
explicit
ContentType
(
const
Mime
::
MediaType
&
mime
)
:
mime_
(
mime
)
UserAgent
()
{
}
explicit
UserAgent
(
const
std
::
string
&
ua
)
:
ua_
(
ua
)
{
}
void
parse
Raw
(
const
char
*
str
,
size_t
len
);
void
parse
(
const
std
::
string
&
data
);
void
write
(
std
::
ostream
&
os
)
const
;
Mime
::
MediaType
mime
()
const
{
return
mime
_
;
}
std
::
string
ua
()
const
{
return
ua
_
;
}
private:
Mime
::
MediaType
mime_
;
std
::
string
ua_
;
};
}
// namespace Header
...
...
tests/headers_test.cc
View file @
b63025ad
...
...
@@ -61,6 +61,106 @@ TEST(headers_test, accept) {
}
TEST
(
headers_test
,
allow
)
{
Header
::
Allow
a1
(
Method
::
Get
);
std
::
ostringstream
os
;
a1
.
write
(
os
);
ASSERT_EQ
(
os
.
str
(),
"GET"
);
os
.
str
(
""
);
Header
::
Allow
a2
({
Method
::
Post
,
Method
::
Put
});
a2
.
write
(
os
);
ASSERT_EQ
(
os
.
str
(),
"POST, PUT"
);
os
.
str
(
""
);
Header
::
Allow
a3
;
a3
.
addMethod
(
Method
::
Get
);
a3
.
write
(
os
);
ASSERT_EQ
(
os
.
str
(),
"GET"
);
os
.
str
(
""
);
a3
.
addMethod
(
Method
::
Options
);
a3
.
write
(
os
);
ASSERT_EQ
(
os
.
str
(),
"GET, OPTIONS"
);
os
.
str
(
""
);
Header
::
Allow
a4
(
Method
::
Head
);
a4
.
addMethods
({
Method
::
Get
,
Method
::
Options
});
a4
.
write
(
os
);
ASSERT_EQ
(
os
.
str
(),
"HEAD, GET, OPTIONS"
);
}
TEST
(
headers_test
,
cache_control
)
{
auto
testTrivial
=
[](
std
::
string
str
,
CacheDirective
::
Directive
expected
)
{
Header
::
CacheControl
cc
;
cc
.
parse
(
str
);
auto
directives
=
cc
.
directives
();
ASSERT_EQ
(
directives
.
size
(),
1
);
ASSERT_EQ
(
directives
[
0
].
directive
(),
expected
);
};
auto
testTimed
=
[](
std
::
string
str
,
CacheDirective
::
Directive
expected
,
uint64_t
delta
)
{
Header
::
CacheControl
cc
;
cc
.
parse
(
str
);
auto
directives
=
cc
.
directives
();
ASSERT_EQ
(
directives
.
size
(),
1
);
ASSERT_EQ
(
directives
[
0
].
directive
(),
expected
);
ASSERT_EQ
(
directives
[
0
].
delta
(),
std
::
chrono
::
seconds
(
delta
));
};
testTrivial
(
"no-cache"
,
CacheDirective
::
NoCache
);
testTrivial
(
"no-store"
,
CacheDirective
::
NoStore
);
testTrivial
(
"no-transform"
,
CacheDirective
::
NoTransform
);
testTrivial
(
"only-if-cached"
,
CacheDirective
::
OnlyIfCached
);
testTimed
(
"max-age=0"
,
CacheDirective
::
MaxAge
,
0
);
testTimed
(
"max-age=12"
,
CacheDirective
::
MaxAge
,
12
);
testTimed
(
"max-stale=12345"
,
CacheDirective
::
MaxStale
,
12345
);
testTimed
(
"min-fresh=48"
,
CacheDirective
::
MinFresh
,
48
);
Header
::
CacheControl
cc1
;
cc1
.
parse
(
"private, max-age=600"
);
auto
d1
=
cc1
.
directives
();
ASSERT_EQ
(
d1
.
size
(),
2
);
ASSERT_EQ
(
d1
[
0
].
directive
(),
CacheDirective
::
Private
);
ASSERT_EQ
(
d1
[
1
].
directive
(),
CacheDirective
::
MaxAge
);
ASSERT_EQ
(
d1
[
1
].
delta
(),
std
::
chrono
::
seconds
(
600
));
Header
::
CacheControl
cc2
;
cc2
.
parse
(
"public, s-maxage=200, proxy-revalidate"
);
auto
d2
=
cc2
.
directives
();
ASSERT_EQ
(
d2
.
size
(),
3
);
ASSERT_EQ
(
d2
[
0
].
directive
(),
CacheDirective
::
Public
);
ASSERT_EQ
(
d2
[
1
].
directive
(),
CacheDirective
::
SMaxAge
);
ASSERT_EQ
(
d2
[
1
].
delta
(),
std
::
chrono
::
seconds
(
200
));
ASSERT_EQ
(
d2
[
2
].
directive
(),
CacheDirective
::
ProxyRevalidate
);
Header
::
CacheControl
cc3
(
CacheDirective
::
NoCache
);
std
::
ostringstream
oss
;
cc3
.
write
(
oss
);
ASSERT_EQ
(
oss
.
str
(),
"no-cache"
);
oss
.
str
(
""
);
cc3
.
addDirective
(
CacheDirective
::
NoStore
);
cc3
.
write
(
oss
);
ASSERT_EQ
(
oss
.
str
(),
"no-cache, no-store"
);
oss
.
str
(
""
);
Header
::
CacheControl
cc4
;
cc4
.
addDirectives
({
CacheDirective
::
Public
,
CacheDirective
(
CacheDirective
::
MaxAge
,
std
::
chrono
::
seconds
(
600
))
});
cc4
.
write
(
oss
);
ASSERT_EQ
(
oss
.
str
(),
"public, max-age=600"
);
}
TEST
(
headers_test
,
content_length
)
{
Header
::
ContentLength
cl
;
...
...
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