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
4035c5f1
Commit
4035c5f1
authored
Jan 19, 2016
by
octal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented cookies parsing
parent
fa382599
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
479 additions
and
8 deletions
+479
-8
main.cc
main.cc
+22
-0
src/CMakeLists.txt
src/CMakeLists.txt
+1
-0
src/cookie.cc
src/cookie.cc
+230
-0
src/cookie.h
src/cookie.h
+99
-0
src/http.cc
src/http.cc
+37
-5
src/http.h
src/http.h
+17
-0
src/http_defs.cc
src/http_defs.cc
+19
-0
src/http_defs.h
src/http_defs.h
+7
-0
src/optional.h
src/optional.h
+2
-2
src/stream.cc
src/stream.cc
+37
-1
src/stream.h
src/stream.h
+4
-0
tests/CMakeLists.txt
tests/CMakeLists.txt
+4
-0
No files found.
main.cc
View file @
4035c5f1
...
...
@@ -2,6 +2,7 @@
#include "peer.h"
#include "http.h"
#include "http_headers.h"
#include "cookie.h"
#include "router.h"
#include <iostream>
#include <cstring>
...
...
@@ -20,6 +21,16 @@ struct ExceptionPrinter {
}
};
void
printCookies
(
const
Net
::
Http
::
Request
&
req
)
{
auto
cookies
=
req
.
cookies
();
std
::
cout
<<
"Cookies: ["
<<
std
::
endl
;
const
std
::
string
indent
(
4
,
' '
);
for
(
const
auto
&
c
:
cookies
)
{
std
::
cout
<<
indent
<<
c
.
name
<<
" = "
<<
c
.
value
<<
std
::
endl
;
}
std
::
cout
<<
"]"
<<
std
::
endl
;
}
class
MyHandler
:
public
Net
::
Http
::
Handler
{
void
onRequest
(
const
Net
::
Http
::
Request
&
req
,
...
...
@@ -41,6 +52,9 @@ class MyHandler : public Net::Http::Handler {
.
add
<
Header
::
Server
>
(
"lys"
)
.
add
<
Header
::
ContentType
>
(
MIME
(
Text
,
Plain
));
response
.
cookies
()
.
add
(
Cookie
(
"lang"
,
"en-US"
));
auto
stream
=
response
.
stream
(
Net
::
Http
::
Code
::
Ok
);
stream
<<
"PO"
;
stream
<<
"NG"
;
...
...
@@ -181,6 +195,7 @@ private:
Routes
::
Post
(
router
,
"/record/:name/:value?"
,
Routes
::
bind
(
&
StatsEndpoint
::
doRecordMetric
,
this
));
Routes
::
Get
(
router
,
"/value/:name"
,
Routes
::
bind
(
&
StatsEndpoint
::
doGetMetric
,
this
));
Routes
::
Get
(
router
,
"/ready"
,
Routes
::
bind
(
&
Generic
::
handleReady
));
Routes
::
Get
(
router
,
"/auth"
,
Routes
::
bind
(
&
StatsEndpoint
::
doAuth
,
this
));
}
...
...
@@ -223,6 +238,13 @@ private:
}
void
doAuth
(
const
Rest
::
Request
&
request
,
Net
::
Http
::
Response
response
)
{
printCookies
(
request
);
response
.
cookies
()
.
add
(
Http
::
Cookie
(
"lang"
,
"en-US"
));
response
.
send
(
Http
::
Code
::
Ok
);
}
class
Metric
{
public:
Metric
(
std
::
string
name
,
int
initialValue
=
1
)
...
...
src/CMakeLists.txt
View file @
4035c5f1
...
...
@@ -11,6 +11,7 @@ set(SOURCE_FILES
http_headers.cc
http_defs.cc
mime.cc
cookie.cc
stream.cc
router.cc
)
...
...
src/cookie.cc
0 → 100644
View file @
4035c5f1
/*
Mathieu Stefani, 16 janvier 2016
Cookie implementation
*/
#include "cookie.h"
#include "stream.h"
#include <iterator>
#include <unordered_map>
namespace
Net
{
namespace
Http
{
namespace
{
StreamCursor
::
Token
matchValue
(
StreamCursor
&
cursor
)
{
int
c
;
if
((
c
=
cursor
.
current
())
!=
StreamCursor
::
Eof
&&
c
!=
'='
)
throw
std
::
runtime_error
(
"Invalid cookie"
);
if
(
!
cursor
.
advance
(
1
))
throw
std
::
runtime_error
(
"Invalid cookie, early eof"
);
StreamCursor
::
Token
token
(
cursor
);
match_until
(
';'
,
cursor
);
return
token
;
}
template
<
typename
T
>
struct
AttributeMatcher
;
template
<
>
struct
AttributeMatcher
<
Optional
<
std
::
string
>>
{
static
void
match
(
StreamCursor
&
cursor
,
Cookie
*
obj
,
Optional
<
std
::
string
>
Cookie
::*
attr
)
{
auto
token
=
matchValue
(
cursor
);
obj
->*
attr
=
Some
(
std
::
string
(
token
.
rawText
(),
token
.
size
()));
}
};
template
<
>
struct
AttributeMatcher
<
Optional
<
int
>>
{
static
void
match
(
StreamCursor
&
cursor
,
Cookie
*
obj
,
Optional
<
int
>
Cookie
::*
attr
)
{
auto
token
=
matchValue
(
cursor
);
auto
strntol
=
[](
const
char
*
str
,
size_t
len
)
{
int
ret
=
0
;
for
(
size_t
i
=
0
;
i
<
len
;
++
i
)
{
if
(
!
isdigit
(
str
[
i
]))
throw
std
::
invalid_argument
(
"Invalid conversion"
);
ret
*=
10
;
ret
+=
str
[
i
]
-
'0'
;
};
return
ret
;
};
obj
->*
attr
=
Some
(
strntol
(
token
.
rawText
(),
token
.
size
()));
}
};
template
<
>
struct
AttributeMatcher
<
bool
>
{
static
void
match
(
StreamCursor
&
cursor
,
Cookie
*
obj
,
bool
Cookie
::*
attr
)
{
obj
->*
attr
=
true
;
}
};
template
<
>
struct
AttributeMatcher
<
Optional
<
FullDate
>>
{
static
void
match
(
StreamCursor
&
cursor
,
Cookie
*
obj
,
Optional
<
FullDate
>
Cookie
::*
attr
)
{
auto
token
=
matchValue
(
cursor
);
obj
->*
attr
=
Some
(
FullDate
::
fromRaw
(
token
.
rawText
(),
token
.
size
()));
}
};
template
<
typename
T
>
bool
match_attribute
(
const
char
*
name
,
size_t
len
,
StreamCursor
&
cursor
,
Cookie
*
obj
,
T
Cookie
::*
attr
)
{
if
(
match_string
(
name
,
len
,
cursor
))
{
AttributeMatcher
<
T
>::
match
(
cursor
,
obj
,
attr
);
cursor
.
advance
(
1
);
return
true
;
}
return
false
;
}
}
Cookie
::
Cookie
(
std
::
string
name
,
std
::
string
value
)
:
name
(
std
::
move
(
name
))
,
value
(
std
::
move
(
value
))
,
secure
(
false
)
,
httpOnly
(
false
)
{
}
Cookie
Cookie
::
fromRaw
(
const
char
*
str
,
size_t
len
)
{
RawStreamBuf
<>
buf
(
const_cast
<
char
*>
(
str
),
len
);
StreamCursor
cursor
(
&
buf
);
StreamCursor
::
Token
nameToken
(
cursor
);
if
(
!
match_until
(
'='
,
cursor
))
throw
std
::
runtime_error
(
"Invalid cookie, missing value"
);
auto
name
=
nameToken
.
text
();
if
(
!
cursor
.
advance
(
1
))
throw
std
::
runtime_error
(
"Invalid cookie, missing value"
);
StreamCursor
::
Token
valueToken
(
cursor
);
match_until
(
';'
,
cursor
);
auto
value
=
valueToken
.
text
();
Cookie
cookie
(
std
::
move
(
name
),
std
::
move
(
value
));
if
(
cursor
.
eof
())
{
return
cookie
;
}
cursor
.
advance
(
1
);
#define STR(str) str, sizeof(str) - 1
int
c
;
do
{
skip_whitespaces
(
cursor
);
if
(
match_attribute
(
STR
(
"Path"
),
cursor
,
&
cookie
,
&
Cookie
::
path
))
;
else
if
(
match_attribute
(
STR
(
"Domain"
),
cursor
,
&
cookie
,
&
Cookie
::
domain
))
;
else
if
(
match_attribute
(
STR
(
"Secure"
),
cursor
,
&
cookie
,
&
Cookie
::
secure
))
;
else
if
(
match_attribute
(
STR
(
"HttpOnly"
),
cursor
,
&
cookie
,
&
Cookie
::
httpOnly
))
;
else
if
(
match_attribute
(
STR
(
"Max-Age"
),
cursor
,
&
cookie
,
&
Cookie
::
maxAge
))
;
else
if
(
match_attribute
(
STR
(
"Expires"
),
cursor
,
&
cookie
,
&
Cookie
::
expires
))
;
// ext
else
{
StreamCursor
::
Token
nameToken
(
cursor
);
match_until
(
'='
,
cursor
);
auto
name
=
nameToken
.
text
();
std
::
string
value
;
if
(
!
cursor
.
eof
())
{
auto
token
=
matchValue
(
cursor
);
value
=
token
.
text
();
}
cookie
.
ext
.
insert
(
std
::
make_pair
(
std
::
move
(
name
),
std
::
move
(
value
)));
}
}
while
(
!
cursor
.
eof
());
#undef STR
return
cookie
;
}
Cookie
Cookie
::
fromString
(
const
std
::
string
&
str
)
{
return
Cookie
::
fromRaw
(
str
.
c_str
(),
str
.
size
());
}
void
Cookie
::
write
(
std
::
ostream
&
os
)
const
{
os
<<
name
<<
"="
<<
value
;
optionally_do
(
path
,
[
&
](
const
std
::
string
&
value
)
{
os
<<
"; "
;
os
<<
"Path="
<<
value
;
});
optionally_do
(
domain
,
[
&
](
const
std
::
string
&
value
)
{
os
<<
"; "
;
os
<<
"Domain="
<<
value
;
});
optionally_do
(
maxAge
,
[
&
](
int
value
)
{
os
<<
"; "
;
os
<<
"Max-Age="
<<
value
;
});
optionally_do
(
expires
,
[
&
](
const
FullDate
&
value
)
{
os
<<
"; "
;
os
<<
"Expires="
;
value
.
write
(
os
);
});
if
(
secure
)
os
<<
"; Secure"
;
if
(
httpOnly
)
os
<<
"; HttpOnly"
;
if
(
!
ext
.
empty
())
{
os
<<
"; "
;
for
(
auto
it
=
std
::
begin
(
ext
),
end
=
std
::
end
(
ext
);
it
!=
end
;
++
it
)
{
os
<<
it
->
first
<<
"="
<<
it
->
second
;
if
(
std
::
distance
(
it
,
end
)
>
1
)
os
<<
"; "
;
}
}
}
CookieJar
::
CookieJar
()
{
}
void
CookieJar
::
add
(
const
Cookie
&
cookie
)
{
cookies
.
insert
(
std
::
make_pair
(
cookie
.
name
,
cookie
));
}
Cookie
CookieJar
::
get
(
const
std
::
string
&
name
)
const
{
auto
it
=
cookies
.
find
(
name
);
if
(
it
==
std
::
end
(
cookies
))
throw
std
::
runtime_error
(
"Could not find requested cookie"
);
return
it
->
second
;
}
bool
CookieJar
::
has
(
const
std
::
string
&
name
)
const
{
auto
it
=
cookies
.
find
(
name
);
return
it
!=
std
::
end
(
cookies
);
}
}
// namespace Http
}
// namespace Net
src/cookie.h
0 → 100644
View file @
4035c5f1
/*
Mathieu Stefani, 16 janvier 2016
Representation of a Cookie as per http://tools.ietf.org/html/rfc6265
*/
#pragma once
#include "optional.h"
#include "http_defs.h"
#include <ctime>
#include <string>
#include <map>
#include <unordered_map>
namespace
Net
{
namespace
Http
{
struct
Cookie
{
Cookie
(
std
::
string
name
,
std
::
string
value
);
std
::
string
name
;
std
::
string
value
;
Optional
<
std
::
string
>
path
;
Optional
<
std
::
string
>
domain
;
Optional
<
FullDate
>
expires
;
Optional
<
int
>
maxAge
;
bool
secure
;
bool
httpOnly
;
std
::
map
<
std
::
string
,
std
::
string
>
ext
;
static
Cookie
fromRaw
(
const
char
*
str
,
size_t
len
);
static
Cookie
fromString
(
const
std
::
string
&
str
);
void
write
(
std
::
ostream
&
os
)
const
;
};
class
CookieJar
{
public:
typedef
std
::
unordered_map
<
std
::
string
,
Cookie
>
Storage
;
struct
iterator
:
std
::
iterator
<
std
::
bidirectional_iterator_tag
,
Cookie
>
{
iterator
(
const
Storage
::
const_iterator
&
iterator
)
:
it_
(
iterator
)
{
}
Cookie
operator
*
()
const
{
return
it_
->
second
;
}
iterator
operator
++
()
{
++
it_
;
return
iterator
(
it_
);
}
iterator
operator
++
(
int
)
{
iterator
ret
(
it_
);
it_
++
;
return
ret
;
}
bool
operator
!=
(
iterator
other
)
const
{
return
it_
!=
other
.
it_
;
}
bool
operator
==
(
iterator
other
)
const
{
return
it_
==
other
.
it_
;
}
private:
Storage
::
const_iterator
it_
;
};
CookieJar
();
void
add
(
const
Cookie
&
cookie
);
Cookie
get
(
const
std
::
string
&
name
)
const
;
bool
has
(
const
std
::
string
&
name
)
const
;
iterator
begin
()
const
{
return
iterator
(
cookies
.
begin
());
}
iterator
end
()
const
{
return
iterator
(
cookies
.
end
());
}
private:
Storage
cookies
;
};
}
// namespace Net
}
// namespace Http
src/http.cc
View file @
4035c5f1
...
...
@@ -64,7 +64,7 @@ namespace {
#define OUT(...) \
do { \
__VA_ARGS__; \
if (!os) return false; \
if (!os)
return false; \
} while (0)
std
::
ostream
os
(
&
buf
);
...
...
@@ -80,6 +80,25 @@ namespace {
#undef OUT
}
bool
writeCookies
(
const
CookieJar
&
cookies
,
DynamicStreamBuf
&
buf
)
{
#define OUT(...) \
do { \
__VA_ARGS__; \
if (!os) return false; \
} while (0)
std
::
ostream
os
(
&
buf
);
for
(
const
auto
&
cookie
:
cookies
)
{
OUT
(
os
<<
"Set-Cookie: "
);
OUT
(
cookie
.
write
(
os
));
OUT
(
os
<<
crlf
);
}
return
true
;
#undef OUT
}
}
namespace
Private
{
...
...
@@ -228,7 +247,13 @@ namespace Private {
if
(
!
cursor
.
advance
(
1
))
return
State
::
Again
;
}
if
(
Header
::
Registry
::
isRegistered
(
name
))
{
if
(
name
==
"Cookie"
)
{
request
->
cookies_
.
add
(
Cookie
::
fromRaw
(
cursor
.
offset
(
start
),
cursor
.
diff
(
start
))
);
}
else
if
(
Header
::
Registry
::
isRegistered
(
name
))
{
std
::
shared_ptr
<
Header
::
Header
>
header
=
Header
::
Registry
::
makeHeader
(
name
);
header
->
parseRaw
(
cursor
.
offset
(
start
),
cursor
.
diff
(
start
));
request
->
headers_
.
add
(
header
);
...
...
@@ -404,6 +429,11 @@ Request::query() const {
return
query_
;
}
const
CookieJar
&
Request
::
cookies
()
const
{
return
cookies_
;
}
#ifdef LIBSTDCPP_SMARTPTR_LOCK_FIXME
std
::
shared_ptr
<
Tcp
::
Peer
>
Request
::
peer
()
const
{
...
...
@@ -428,15 +458,16 @@ ResponseStream::ResponseStream(
if
(
!
writeStatusLine
(
code_
,
buf_
))
throw
Error
(
"Response exceeded buffer size"
);
if
(
!
writeCookies
(
cookies_
,
buf_
))
{
throw
Error
(
"Response exceeded buffer size"
);
}
if
(
writeHeaders
(
headers_
,
buf_
))
{
std
::
ostream
os
(
&
buf_
);
if
(
!
writeHeader
<
Header
::
TransferEncoding
>
(
os
,
Header
::
Encoding
::
Chunked
))
throw
Error
(
"Response exceeded buffer size"
);
os
<<
crlf
;
}
else
{
throw
Error
(
"Response exceeded buffer size"
);
}
}
void
...
...
@@ -479,6 +510,7 @@ Response::putOnWire(const char* data, size_t len)
OUT
(
writeStatusLine
(
code_
,
buf_
));
OUT
(
writeHeaders
(
headers_
,
buf_
));
OUT
(
writeCookies
(
cookies_
,
buf_
));
OUT
(
writeHeader
<
Header
::
ContentLength
>
(
os
,
len
));
...
...
src/http.h
View file @
4035c5f1
...
...
@@ -14,6 +14,7 @@
#include "net.h"
#include "http_headers.h"
#include "http_defs.h"
#include "cookie.h"
#include "stream.h"
#include "mime.h"
#include "async.h"
...
...
@@ -53,6 +54,8 @@ public:
Header
::
Collection
headers_
;
std
::
string
body_
;
CookieJar
cookies_
;
};
namespace
Uri
{
...
...
@@ -91,6 +94,8 @@ public:
const
Header
::
Collection
&
headers
()
const
;
const
Uri
::
Query
&
query
()
const
;
const
CookieJar
&
cookies
()
const
;
/* @Investigate: this is disabled because of a lock in the shared_ptr / weak_ptr
implementation of libstdc++. Under contention, we experience a performance
drop of 5x with that lock
...
...
@@ -208,6 +213,10 @@ public:
return
headers_
;
}
const
CookieJar
&
cookies
()
const
{
return
cookies_
;
}
Code
code
()
const
{
return
code_
;
}
...
...
@@ -295,6 +304,14 @@ public:
return
headers_
;
}
const
CookieJar
&
cookies
()
const
{
return
cookies_
;
}
CookieJar
&
cookies
()
{
return
cookies_
;
}
Code
code
()
const
{
return
code_
;
}
...
...
src/http_defs.cc
View file @
4035c5f1
...
...
@@ -7,6 +7,7 @@
#include "http_defs.h"
#include "common.h"
#include <iostream>
#include <iomanip>
namespace
Net
{
...
...
@@ -107,6 +108,24 @@ FullDate::fromString(const std::string& str) {
return
FullDate
::
fromRaw
(
str
.
c_str
(),
str
.
size
());
}
void
FullDate
::
write
(
std
::
ostream
&
os
,
Type
type
)
const
{
char
buff
[
100
];
std
::
memset
(
buff
,
0
,
sizeof
buff
);
switch
(
type
)
{
case
Type
:
:
RFC1123
:
//os << std::put_time(&date_, "%a, %d %b %Y %H:%M:%S %Z");
if
(
std
::
strftime
(
buff
,
sizeof
buff
,
"%a, %d %b %Y %H:%M:%S %Z"
,
&
date_
))
os
<<
buff
;
break
;
case
Type
:
:
RFC850
:
case
Type
:
:
AscTime
:
break
;
}
}
const
char
*
methodString
(
Method
method
)
{
switch
(
method
)
{
...
...
src/http_defs.h
View file @
4035c5f1
...
...
@@ -147,11 +147,18 @@ class FullDate {
public:
FullDate
();
enum
class
Type
{
RFC1123
,
RFC850
,
AscTime
};
FullDate
(
std
::
tm
date
)
:
date_
(
date
)
{
}
std
::
tm
date
()
const
{
return
date_
;
}
void
write
(
std
::
ostream
&
os
,
Type
type
=
Type
::
RFC1123
)
const
;
static
FullDate
fromRaw
(
const
char
*
str
,
size_t
len
);
static
FullDate
fromString
(
const
std
::
string
&
str
);
...
...
src/optional.h
View file @
4035c5f1
...
...
@@ -118,7 +118,7 @@ public:
template
<
typename
U
>
Optional
(
types
::
Some
<
U
>
some
)
{
static_assert
(
std
::
is_same
<
T
,
U
>::
value
||
std
::
is_convertible
<
T
,
U
>::
value
,
static_assert
(
std
::
is_same
<
T
,
U
>::
value
||
std
::
is_convertible
<
U
,
T
>::
value
,
"Types mismatch"
);
from_some_helper
(
std
::
move
(
some
),
types
::
is_move_constructible
<
U
>
());
}
...
...
@@ -126,7 +126,7 @@ public:
template
<
typename
U
>
Optional
<
T
>
&
operator
=
(
types
::
Some
<
U
>
some
)
{
static_assert
(
std
::
is_same
<
T
,
U
>::
value
||
std
::
is_convertible
<
T
,
U
>::
value
,
static_assert
(
std
::
is_same
<
T
,
U
>::
value
||
std
::
is_convertible
<
U
,
T
>::
value
,
"Types mismatch"
);
if
(
none_flag
!=
NoneMarker
)
{
data
()
->~
T
();
...
...
src/stream.cc
View file @
4035c5f1
...
...
@@ -143,13 +143,38 @@ match_raw(const void* buf, size_t len, StreamCursor& cursor) {
return
false
;
}
bool
match_string
(
const
char
*
str
,
size_t
len
,
StreamCursor
&
cursor
,
CaseSensitivity
cs
)
{
if
(
cursor
.
remaining
()
<
len
)
return
false
;
if
(
cs
==
CaseSensitivity
::
Sensitive
)
{
if
(
strncmp
(
cursor
.
offset
(),
str
,
len
)
==
0
)
{
cursor
.
advance
(
len
);
return
true
;
}
}
else
{
const
char
*
off
=
cursor
.
offset
();
for
(
size_t
i
=
0
;
i
<
len
;
++
i
)
{
const
char
lhs
=
std
::
tolower
(
str
[
i
]);
const
char
rhs
=
std
::
tolower
(
off
[
i
]);
if
(
lhs
!=
rhs
)
return
false
;
}
cursor
.
advance
(
len
);
return
true
;
}
return
false
;
}
bool
match_literal
(
char
c
,
StreamCursor
&
cursor
,
CaseSensitivity
cs
)
{
if
(
cursor
.
eof
())
return
false
;
char
lhs
=
(
cs
==
CaseSensitivity
::
Sensitive
?
c
:
std
::
tolower
(
c
));
char
rhs
=
(
cs
==
CaseSensitivity
::
Ins
ensitive
?
cursor
.
current
()
:
std
::
tolower
(
cursor
.
current
()));
char
rhs
=
(
cs
==
CaseSensitivity
::
S
ensitive
?
cursor
.
current
()
:
std
::
tolower
(
cursor
.
current
()));
if
(
lhs
==
rhs
)
{
cursor
.
advance
(
1
);
...
...
@@ -200,3 +225,14 @@ match_double(double* val, StreamCursor &cursor) {
cursor
.
advance
(
static_cast
<
ptrdiff_t
>
(
end
-
cursor
.
offset
()));
return
true
;
}
void
skip_whitespaces
(
StreamCursor
&
cursor
)
{
if
(
cursor
.
eof
())
return
;
int
c
;
while
((
c
=
cursor
.
current
())
!=
StreamCursor
::
Eof
&&
(
c
==
' '
||
c
==
'\t'
))
{
cursor
.
advance
(
1
);
}
}
src/stream.h
View file @
4035c5f1
...
...
@@ -316,7 +316,11 @@ enum class CaseSensitivity {
};
bool
match_raw
(
const
void
*
buf
,
size_t
len
,
StreamCursor
&
cursor
);
bool
match_string
(
const
char
*
str
,
size_t
len
,
StreamCursor
&
cursor
,
CaseSensitivity
cs
=
CaseSensitivity
::
Insensitive
);
bool
match_literal
(
char
c
,
StreamCursor
&
cursor
,
CaseSensitivity
cs
=
CaseSensitivity
::
Insensitive
);
bool
match_until
(
char
c
,
StreamCursor
&
cursor
,
CaseSensitivity
cs
=
CaseSensitivity
::
Insensitive
);
bool
match_until
(
std
::
initializer_list
<
char
>
chars
,
StreamCursor
&
cursor
,
CaseSensitivity
cs
=
CaseSensitivity
::
Insensitive
);
bool
match_double
(
double
*
val
,
StreamCursor
&
cursor
);
void
skip_whitespaces
(
StreamCursor
&
cursor
);
tests/CMakeLists.txt
View file @
4035c5f1
...
...
@@ -17,3 +17,7 @@ add_test( typeid_test run_typeid_test )
add_executable
(
run_router_test router_test.cc
)
target_link_libraries
(
run_router_test gtest gtest_main net
)
add_test
(
router_test run_router_test
)
add_executable
(
run_cookie_test cookie_test.cc
)
target_link_libraries
(
run_cookie_test gtest gtest_main net
)
add_test
(
cookie_test run_cookie_test
)
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