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
bb9909a2
Commit
bb9909a2
authored
Aug 29, 2015
by
Mathieu STEFANI
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Mimes are now in their own header / source files
parent
5465db8b
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
530 additions
and
492 deletions
+530
-492
src/CMakeLists.txt
src/CMakeLists.txt
+1
-0
src/http_header.cc
src/http_header.cc
+0
-285
src/http_header.h
src/http_header.h
+1
-206
src/mime.cc
src/mime.cc
+305
-0
src/mime.h
src/mime.h
+222
-0
tests/mime_test.cc
tests/mime_test.cc
+1
-1
No files found.
src/CMakeLists.txt
View file @
bb9909a2
...
@@ -7,6 +7,7 @@ set(SOURCE_FILES
...
@@ -7,6 +7,7 @@ set(SOURCE_FILES
http.cc
http.cc
http_header.cc
http_header.cc
http_headers.cc
http_headers.cc
mime.cc
)
)
add_library
(
net
${
SOURCE_FILES
}
)
add_library
(
net
${
SOURCE_FILES
}
)
...
...
src/http_header.cc
View file @
bb9909a2
...
@@ -18,291 +18,6 @@ namespace Net {
...
@@ -18,291 +18,6 @@ namespace Net {
namespace
Http
{
namespace
Http
{
namespace
Mime
{
std
::
string
Q
::
toString
()
const
{
if
(
val_
==
0
)
return
"q=0"
;
else
if
(
val_
==
100
)
return
"q=1"
;
char
buff
[
sizeof
(
"q=0.99"
)];
memset
(
buff
,
sizeof
buff
,
0
);
if
(
val_
%
10
==
0
)
snprintf
(
buff
,
sizeof
buff
,
"q=%.1f"
,
val_
/
100.0
);
else
snprintf
(
buff
,
sizeof
buff
,
"q=%.2f"
,
val_
/
100.0
);
return
std
::
string
(
buff
);
}
MediaType
MediaType
::
fromString
(
const
std
::
string
&
str
)
{
return
fromRaw
(
str
.
c_str
(),
str
.
size
());
}
MediaType
MediaType
::
fromString
(
std
::
string
&&
str
)
{
return
fromRaw
(
str
.
c_str
(),
str
.
size
());
}
MediaType
MediaType
::
fromRaw
(
const
char
*
str
,
size_t
len
)
{
MediaType
res
;
res
.
parseRaw
(
str
,
len
);
return
res
;
}
void
MediaType
::
parseRaw
(
const
char
*
str
,
size_t
len
)
{
auto
eof
=
[
&
](
const
char
*
p
)
{
return
p
-
str
==
len
;
};
auto
offset
=
[
&
](
const
char
*
ptr
)
{
return
static_cast
<
size_t
>
(
ptr
-
str
);
};
auto
raise
=
[
&
](
const
char
*
str
)
{
// TODO: eventually, we should throw a more generic exception
// that could then be catched in lower stack frames to rethrow
// an HttpError
throw
HttpError
(
Http
::
Code
::
Unsupported_Media_Type
,
str
);
};
// Macro to ensure that we do not overflow when comparing strings
// The trick here is to use sizeof on a raw string literal of type
// const char[N] instead of strlen to avoid additional
// runtime computation
#define MAX_SIZE(s) std::min(sizeof(s) - 1, len - offset(p))
// Parse type
const
char
*
p
=
strchr
(
str
,
'/'
);
if
(
p
==
NULL
)
{
raise
(
"Malformated Media Type"
);
}
raw_
=
string
(
str
,
len
);
Mime
::
Type
top
;
// The reason we are using a do { } while (0); syntax construct here is to emulate
// if / else-if. Since we are using items-list macros to compare the strings,
// we want to avoid evaluating all the branches when one of them evaluates to true.
//
// Instead, we break the loop when a branch evaluates to true so that we do
// not evaluate all the subsequent ones.
//
// Watch out, this pattern is repeated throughout the function
do
{
#define TYPE(val, s) \
if (memcmp(str, s, MAX_SIZE(s)) == 0) { \
top = Type::val; \
break; \
}
MIME_TYPES
#undef TYPE
raise
(
"Unknown Media Type"
);
}
while
(
0
);
top_
=
top
;
// Parse subtype
Mime
::
Subtype
sub
;
++
p
;
if
(
eof
(
p
))
raise
(
"Malformed Media Type"
);
if
(
memcmp
(
p
,
"vnd."
,
MAX_SIZE
(
"vnd."
))
==
0
)
{
sub
=
Subtype
::
Vendor
;
}
else
{
do
{
#define SUB_TYPE(val, s) \
if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
sub = Subtype::val; \
p += sizeof(s) - 1; \
break; \
}
MIME_SUBTYPES
#undef SUB_TYPE
sub
=
Subtype
::
Ext
;
}
while
(
0
);
}
if
(
sub
==
Subtype
::
Ext
||
sub
==
Subtype
::
Vendor
)
{
rawSubIndex
.
beg
=
offset
(
p
);
while
(
!
eof
(
p
)
&&
(
*
p
!=
';'
&&
*
p
!=
'+'
))
++
p
;
rawSubIndex
.
end
=
offset
(
p
)
-
1
;
}
sub_
=
sub
;
if
(
eof
(
p
))
return
;
// Parse suffix
Mime
::
Suffix
suffix
=
Suffix
::
None
;
if
(
*
p
==
'+'
)
{
++
p
;
if
(
eof
(
p
))
raise
(
"Malformed Media Type"
);
do
{
#define SUFFIX(val, s, _) \
if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
suffix = Suffix::val; \
p += sizeof(s) - 1; \
break; \
}
MIME_SUFFIXES
#undef SUFFIX
suffix
=
Suffix
::
Ext
;
}
while
(
0
);
if
(
suffix
==
Suffix
::
Ext
)
{
rawSuffixIndex
.
beg
=
offset
(
p
);
while
(
!
eof
(
p
)
&&
(
*
p
!=
';'
&&
*
p
!=
'+'
))
++
p
;
rawSuffixIndex
.
end
=
offset
(
p
)
-
1
;
}
suffix_
=
suffix
;
}
// Parse parameters
while
(
!
eof
(
p
))
{
if
(
*
p
==
';'
||
*
p
==
' '
)
{
if
(
eof
(
p
+
1
))
raise
(
"Malformed Media Type"
);
++
p
;
}
else
if
(
*
p
==
'q'
)
{
++
p
;
if
(
eof
(
p
))
{
raise
(
"Invalid quality factor"
);
}
if
(
*
p
==
'='
)
{
char
*
end
;
double
val
=
strtod
(
p
+
1
,
&
end
);
if
(
!
eof
(
end
)
&&
*
end
!=
';'
&&
*
end
!=
' '
)
{
raise
(
"Invalid quality factor"
);
}
q_
=
Some
(
Q
::
fromFloat
(
val
));
p
=
end
;
}
else
{
raise
(
"Invalid quality factor"
);
}
}
else
{
const
char
*
begin
=
p
;
while
(
!
eof
(
p
)
&&
*
p
!=
'='
)
++
p
;
if
(
eof
(
p
))
raise
(
"Unfinished Media Type parameter"
);
const
char
*
end
=
p
;
++
p
;
if
(
eof
(
p
))
raise
(
"Unfinished Media Type parameter"
);
std
::
string
key
(
begin
,
end
);
begin
=
p
;
while
(
!
eof
(
p
)
&&
*
p
!=
' '
&&
*
p
!=
';'
)
++
p
;
std
::
string
value
(
begin
,
p
);
params
.
insert
(
std
::
make_pair
(
std
::
move
(
key
),
std
::
move
(
value
)));
}
}
#undef MAX_SIZE
}
void
MediaType
::
setQuality
(
Q
quality
)
{
q_
=
Some
(
quality
);
}
Optional
<
std
::
string
>
MediaType
::
getParam
(
std
::
string
name
)
const
{
auto
it
=
params
.
find
(
name
);
if
(
it
==
std
::
end
(
params
))
{
return
None
();
}
return
Some
(
it
->
second
);
}
void
MediaType
::
setParam
(
std
::
string
name
,
std
::
string
value
)
{
params
[
name
]
=
value
;
}
std
::
string
MediaType
::
toString
()
const
{
if
(
!
raw_
.
empty
())
return
raw_
;
auto
topString
=
[](
Mime
::
Type
top
)
->
const
char
*
{
switch
(
top
)
{
#define TYPE(val, str) \
case Mime::Type::val: \
return str;
MIME_TYPES
#undef TYPE
}
};
auto
subString
=
[](
Mime
::
Subtype
sub
)
->
const
char
*
{
switch
(
sub
)
{
#define SUB_TYPE(val, str) \
case Mime::Subtype::val: \
return str;
MIME_SUBTYPES
#undef TYPE
}
};
auto
suffixString
=
[](
Mime
::
Suffix
suffix
)
->
const
char
*
{
switch
(
suffix
)
{
#define SUFFIX(val, str, _) \
case Mime::Suffix::val: \
return "+" str;
MIME_SUFFIXES
#undef SUFFIX
}
};
// @Improvement: allocating and concatenating many small strings is probably slow
std
::
string
res
;
res
+=
topString
(
top_
);
res
+=
"/"
;
res
+=
subString
(
sub_
);
if
(
suffix_
!=
Suffix
::
None
)
{
res
+=
suffixString
(
suffix_
);
}
optionally_do
(
q_
,
[
&
res
](
Q
quality
)
{
res
+=
"; "
;
res
+=
quality
.
toString
();
});
for
(
const
auto
&
param
:
params
)
{
res
+=
"; "
;
res
+=
param
.
first
+
"="
+
param
.
second
;
}
return
res
;
}
}
// namespace Mime
const
char
*
encodingString
(
Encoding
encoding
)
{
const
char
*
encodingString
(
Encoding
encoding
)
{
switch
(
encoding
)
{
switch
(
encoding
)
{
case
Encoding
:
:
Gzip
:
case
Encoding
:
:
Gzip
:
...
...
src/http_header.h
View file @
bb9909a2
...
@@ -6,15 +6,12 @@
...
@@ -6,15 +6,12 @@
#pragma once
#pragma once
#include "
optional
.h"
#include "
mime
.h"
#include <string>
#include <string>
#include <type_traits>
#include <type_traits>
#include <memory>
#include <memory>
#include <ostream>
#include <ostream>
#include <vector>
#include <vector>
#include <stdexcept>
#include <cassert>
#include <unordered_map>
#define SAFE_HEADER_CAST
#define SAFE_HEADER_CAST
...
@@ -65,208 +62,6 @@ enum class Encoding {
...
@@ -65,208 +62,6 @@ enum class Encoding {
const
char
*
encodingString
(
Encoding
encoding
);
const
char
*
encodingString
(
Encoding
encoding
);
namespace
Mime
{
#define MIME_TYPES \
TYPE(Star , "*") \
TYPE(Text , "text") \
TYPE(Image , "image") \
TYPE(Audio , "audio") \
TYPE(Video , "video") \
TYPE(Application, "application") \
TYPE(Message , "message") \
TYPE(Multipart , "multipart")
#define MIME_SUBTYPES \
SUB_TYPE(Star , "*") \
SUB_TYPE(Plain , "plain") \
SUB_TYPE(Html , "html") \
SUB_TYPE(Xhtml , "xhtml") \
SUB_TYPE(Xml , "xml") \
SUB_TYPE(Javascript, "javascript") \
SUB_TYPE(Css , "css") \
\
SUB_TYPE(Json , "json") \
SUB_TYPE(FormUrlEncoded, "x-www-form-urlencoded") \
\
SUB_TYPE(Png, "png") \
SUB_TYPE(Gif, "gif") \
SUB_TYPE(Bmp, "bmp") \
SUB_TYPE(Jpeg, "jpeg")
#define MIME_SUFFIXES \
SUFFIX(Json , "json" , "JavaScript Object Notation") \
SUFFIX(Ber , "ber" , "Basic Encoding Rules") \
SUFFIX(Der , "der" , "Distinguished Encoding Rules") \
SUFFIX(Fastinfoset, "fastinfoset", "Fast Infoset") \
SUFFIX(Wbxml , "wbxml" , "WAP Binary XML") \
SUFFIX(Zip , "zip" , "ZIP file storage") \
SUFFIX(Xml , "xml" , "Extensible Markup Language")
enum
class
Type
{
#define TYPE(val, _) val,
MIME_TYPES
#undef TYPE
None
};
enum
class
Subtype
{
#define SUB_TYPE(val, _) val,
MIME_SUBTYPES
#undef SUB_TYPE
Vendor
,
Ext
,
None
};
enum
class
Suffix
{
#define SUFFIX(val, _, __) val,
MIME_SUFFIXES
#undef SUFFIX
None
,
Ext
};
// 3.9 Quality Values
class
Q
{
public:
// typedef uint8_t Type;
typedef
uint16_t
Type
;
explicit
Q
(
Type
val
)
{
if
(
val
>
100
)
{
throw
std
::
runtime_error
(
"Invalid quality value, must be in the [0; 100] range"
);
}
val_
=
val
;
}
static
Q
fromFloat
(
double
f
)
{
return
Q
(
static_cast
<
Type
>
(
f
*
100.0
));
}
Type
value
()
const
{
return
val_
;
}
operator
Type
()
const
{
return
val_
;
}
std
::
string
toString
()
const
;
private:
Type
val_
;
};
inline
bool
operator
==
(
Q
lhs
,
Q
rhs
)
{
return
lhs
.
value
()
==
rhs
.
value
();
}
// 3.7 Media Types
class
MediaType
{
public:
enum
Parse
{
DoParse
,
DontParse
};
MediaType
()
:
top_
(
Type
::
None
)
,
sub_
(
Subtype
::
None
)
,
suffix_
(
Suffix
::
None
)
{
}
MediaType
(
std
::
string
raw
,
Parse
parse
=
DontParse
)
:
top_
(
Type
::
None
)
,
sub_
(
Subtype
::
None
)
,
suffix_
(
Suffix
::
None
)
{
if
(
parse
==
DoParse
)
{
parseRaw
(
raw
.
c_str
(),
raw
.
length
());
}
else
{
raw_
=
std
::
move
(
raw
);
}
}
MediaType
(
Mime
::
Type
top
,
Mime
::
Subtype
sub
)
:
top_
(
top
)
,
sub_
(
sub
)
,
suffix_
(
Suffix
::
None
)
{
}
MediaType
(
Mime
::
Type
top
,
Mime
::
Subtype
sub
,
Mime
::
Suffix
suffix
)
:
top_
(
top
)
,
sub_
(
sub
)
,
suffix_
(
suffix
)
{
}
static
MediaType
fromRaw
(
const
char
*
str
,
size_t
len
);
static
MediaType
fromString
(
const
std
::
string
&
str
);
static
MediaType
fromString
(
std
::
string
&&
str
);
Mime
::
Type
top
()
const
{
return
top_
;
}
Mime
::
Subtype
sub
()
const
{
return
sub_
;
}
Mime
::
Suffix
suffix
()
const
{
return
suffix_
;
}
std
::
string
rawSub
()
const
{
return
rawSubIndex
.
splice
(
raw_
);
}
std
::
string
raw
()
const
{
return
raw_
;
}
const
Optional
<
Q
>&
q
()
const
{
return
q_
;
}
void
setQuality
(
Q
quality
);
Optional
<
std
::
string
>
getParam
(
std
::
string
name
)
const
;
void
setParam
(
std
::
string
name
,
std
::
string
value
);
std
::
string
toString
()
const
;
private:
void
parseRaw
(
const
char
*
str
,
size_t
len
);
Mime
::
Type
top_
;
Mime
::
Subtype
sub_
;
Mime
::
Suffix
suffix_
;
/* Let's save some extra memory allocations by only storing the
raw MediaType along with indexes of the relevant parts
Note: experimental for now as it might not be a good idea
*/
std
::
string
raw_
;
struct
Index
{
size_t
beg
;
size_t
end
;
std
::
string
splice
(
const
std
::
string
&
str
)
const
{
assert
(
end
>=
beg
);
return
str
.
substr
(
beg
,
end
-
beg
+
1
);
}
};
Index
rawSubIndex
;
Index
rawSuffixIndex
;
std
::
unordered_map
<
std
::
string
,
std
::
string
>
params
;
Optional
<
Q
>
q_
;
};
inline
bool
operator
==
(
const
MediaType
&
lhs
,
const
MediaType
&
rhs
)
{
return
lhs
.
top
()
==
rhs
.
top
()
&&
lhs
.
sub
()
==
rhs
.
sub
()
&&
lhs
.
suffix
()
==
rhs
.
suffix
();
}
}
// namespace Mime
#define MIME(top, sub) \
Net::Http::Mime::MediaType(Net::Http::Mime::Type::top, Net::Http::Mime::Subtype::sub)
#define MIME3(top, sub, suffix) \
Net::Http::Mime::MediaType(Net::Http::Mime::Type::top, Net::Http::Mime::Subtype::sub, Net::Http::Mime::Suffix::suffix);
class
Header
{
class
Header
{
public:
public:
virtual
const
char
*
name
()
const
=
0
;
virtual
const
char
*
name
()
const
=
0
;
...
...
src/mime.cc
0 → 100644
View file @
bb9909a2
/* mime.cc
Mathieu Stefani, 29 August 2015
Implementaton of MIME Type parsing
*/
#include "mime.h"
#include "http.h"
#include <cstring>
using
namespace
std
;
namespace
Net
{
namespace
Http
{
namespace
Mime
{
std
::
string
Q
::
toString
()
const
{
if
(
val_
==
0
)
return
"q=0"
;
else
if
(
val_
==
100
)
return
"q=1"
;
char
buff
[
sizeof
(
"q=0.99"
)];
memset
(
buff
,
sizeof
buff
,
0
);
if
(
val_
%
10
==
0
)
snprintf
(
buff
,
sizeof
buff
,
"q=%.1f"
,
val_
/
100.0
);
else
snprintf
(
buff
,
sizeof
buff
,
"q=%.2f"
,
val_
/
100.0
);
return
std
::
string
(
buff
);
}
MediaType
MediaType
::
fromString
(
const
std
::
string
&
str
)
{
return
fromRaw
(
str
.
c_str
(),
str
.
size
());
}
MediaType
MediaType
::
fromString
(
std
::
string
&&
str
)
{
return
fromRaw
(
str
.
c_str
(),
str
.
size
());
}
MediaType
MediaType
::
fromRaw
(
const
char
*
str
,
size_t
len
)
{
MediaType
res
;
res
.
parseRaw
(
str
,
len
);
return
res
;
}
void
MediaType
::
parseRaw
(
const
char
*
str
,
size_t
len
)
{
auto
eof
=
[
&
](
const
char
*
p
)
{
return
p
-
str
==
len
;
};
auto
offset
=
[
&
](
const
char
*
ptr
)
{
return
static_cast
<
size_t
>
(
ptr
-
str
);
};
auto
raise
=
[
&
](
const
char
*
str
)
{
// TODO: eventually, we should throw a more generic exception
// that could then be catched in lower stack frames to rethrow
// an HttpError
throw
HttpError
(
Http
::
Code
::
Unsupported_Media_Type
,
str
);
};
// Macro to ensure that we do not overflow when comparing strings
// The trick here is to use sizeof on a raw string literal of type
// const char[N] instead of strlen to avoid additional
// runtime computation
#define MAX_SIZE(s) std::min(sizeof(s) - 1, len - offset(p))
// Parse type
const
char
*
p
=
strchr
(
str
,
'/'
);
if
(
p
==
NULL
)
{
raise
(
"Malformated Media Type"
);
}
raw_
=
string
(
str
,
len
);
Mime
::
Type
top
;
// The reason we are using a do { } while (0); syntax construct here is to emulate
// if / else-if. Since we are using items-list macros to compare the strings,
// we want to avoid evaluating all the branches when one of them evaluates to true.
//
// Instead, we break the loop when a branch evaluates to true so that we do
// not evaluate all the subsequent ones.
//
// Watch out, this pattern is repeated throughout the function
do
{
#define TYPE(val, s) \
if (memcmp(str, s, MAX_SIZE(s)) == 0) { \
top = Type::val; \
break; \
}
MIME_TYPES
#undef TYPE
raise
(
"Unknown Media Type"
);
}
while
(
0
);
top_
=
top
;
// Parse subtype
Mime
::
Subtype
sub
;
++
p
;
if
(
eof
(
p
))
raise
(
"Malformed Media Type"
);
if
(
memcmp
(
p
,
"vnd."
,
MAX_SIZE
(
"vnd."
))
==
0
)
{
sub
=
Subtype
::
Vendor
;
}
else
{
do
{
#define SUB_TYPE(val, s) \
if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
sub = Subtype::val; \
p += sizeof(s) - 1; \
break; \
}
MIME_SUBTYPES
#undef SUB_TYPE
sub
=
Subtype
::
Ext
;
}
while
(
0
);
}
if
(
sub
==
Subtype
::
Ext
||
sub
==
Subtype
::
Vendor
)
{
rawSubIndex
.
beg
=
offset
(
p
);
while
(
!
eof
(
p
)
&&
(
*
p
!=
';'
&&
*
p
!=
'+'
))
++
p
;
rawSubIndex
.
end
=
offset
(
p
)
-
1
;
}
sub_
=
sub
;
if
(
eof
(
p
))
return
;
// Parse suffix
Mime
::
Suffix
suffix
=
Suffix
::
None
;
if
(
*
p
==
'+'
)
{
++
p
;
if
(
eof
(
p
))
raise
(
"Malformed Media Type"
);
do
{
#define SUFFIX(val, s, _) \
if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
suffix = Suffix::val; \
p += sizeof(s) - 1; \
break; \
}
MIME_SUFFIXES
#undef SUFFIX
suffix
=
Suffix
::
Ext
;
}
while
(
0
);
if
(
suffix
==
Suffix
::
Ext
)
{
rawSuffixIndex
.
beg
=
offset
(
p
);
while
(
!
eof
(
p
)
&&
(
*
p
!=
';'
&&
*
p
!=
'+'
))
++
p
;
rawSuffixIndex
.
end
=
offset
(
p
)
-
1
;
}
suffix_
=
suffix
;
}
// Parse parameters
while
(
!
eof
(
p
))
{
if
(
*
p
==
';'
||
*
p
==
' '
)
{
if
(
eof
(
p
+
1
))
raise
(
"Malformed Media Type"
);
++
p
;
}
else
if
(
*
p
==
'q'
)
{
++
p
;
if
(
eof
(
p
))
{
raise
(
"Invalid quality factor"
);
}
if
(
*
p
==
'='
)
{
char
*
end
;
double
val
=
strtod
(
p
+
1
,
&
end
);
if
(
!
eof
(
end
)
&&
*
end
!=
';'
&&
*
end
!=
' '
)
{
raise
(
"Invalid quality factor"
);
}
q_
=
Some
(
Q
::
fromFloat
(
val
));
p
=
end
;
}
else
{
raise
(
"Invalid quality factor"
);
}
}
else
{
const
char
*
begin
=
p
;
while
(
!
eof
(
p
)
&&
*
p
!=
'='
)
++
p
;
if
(
eof
(
p
))
raise
(
"Unfinished Media Type parameter"
);
const
char
*
end
=
p
;
++
p
;
if
(
eof
(
p
))
raise
(
"Unfinished Media Type parameter"
);
std
::
string
key
(
begin
,
end
);
begin
=
p
;
while
(
!
eof
(
p
)
&&
*
p
!=
' '
&&
*
p
!=
';'
)
++
p
;
std
::
string
value
(
begin
,
p
);
params
.
insert
(
std
::
make_pair
(
std
::
move
(
key
),
std
::
move
(
value
)));
}
}
#undef MAX_SIZE
}
void
MediaType
::
setQuality
(
Q
quality
)
{
q_
=
Some
(
quality
);
}
Optional
<
std
::
string
>
MediaType
::
getParam
(
std
::
string
name
)
const
{
auto
it
=
params
.
find
(
name
);
if
(
it
==
std
::
end
(
params
))
{
return
None
();
}
return
Some
(
it
->
second
);
}
void
MediaType
::
setParam
(
std
::
string
name
,
std
::
string
value
)
{
params
[
name
]
=
value
;
}
std
::
string
MediaType
::
toString
()
const
{
if
(
!
raw_
.
empty
())
return
raw_
;
auto
topString
=
[](
Mime
::
Type
top
)
->
const
char
*
{
switch
(
top
)
{
#define TYPE(val, str) \
case Mime::Type::val: \
return str;
MIME_TYPES
#undef TYPE
}
};
auto
subString
=
[](
Mime
::
Subtype
sub
)
->
const
char
*
{
switch
(
sub
)
{
#define SUB_TYPE(val, str) \
case Mime::Subtype::val: \
return str;
MIME_SUBTYPES
#undef TYPE
}
};
auto
suffixString
=
[](
Mime
::
Suffix
suffix
)
->
const
char
*
{
switch
(
suffix
)
{
#define SUFFIX(val, str, _) \
case Mime::Suffix::val: \
return "+" str;
MIME_SUFFIXES
#undef SUFFIX
}
};
// @Improvement: allocating and concatenating many small strings is probably slow
std
::
string
res
;
res
+=
topString
(
top_
);
res
+=
"/"
;
res
+=
subString
(
sub_
);
if
(
suffix_
!=
Suffix
::
None
)
{
res
+=
suffixString
(
suffix_
);
}
optionally_do
(
q_
,
[
&
res
](
Q
quality
)
{
res
+=
"; "
;
res
+=
quality
.
toString
();
});
for
(
const
auto
&
param
:
params
)
{
res
+=
"; "
;
res
+=
param
.
first
+
"="
+
param
.
second
;
}
return
res
;
}
}
// namespace Mime
}
// namespace Http
}
// namespace Net
src/mime.h
0 → 100644
View file @
bb9909a2
/* mime.h
Mathieu Stefani, 29 August 2015
Type safe representation of a MIME Type (RFC 1590)
*/
#pragma once
#include "optional.h"
#include <string>
#include <unordered_map>
#include <stdexcept>
#include <cassert>
namespace
Net
{
namespace
Http
{
namespace
Mime
{
#define MIME_TYPES \
TYPE(Star , "*") \
TYPE(Text , "text") \
TYPE(Image , "image") \
TYPE(Audio , "audio") \
TYPE(Video , "video") \
TYPE(Application, "application") \
TYPE(Message , "message") \
TYPE(Multipart , "multipart")
#define MIME_SUBTYPES \
SUB_TYPE(Star , "*") \
SUB_TYPE(Plain , "plain") \
SUB_TYPE(Html , "html") \
SUB_TYPE(Xhtml , "xhtml") \
SUB_TYPE(Xml , "xml") \
SUB_TYPE(Javascript, "javascript") \
SUB_TYPE(Css , "css") \
\
SUB_TYPE(Json , "json") \
SUB_TYPE(FormUrlEncoded, "x-www-form-urlencoded") \
\
SUB_TYPE(Png, "png") \
SUB_TYPE(Gif, "gif") \
SUB_TYPE(Bmp, "bmp") \
SUB_TYPE(Jpeg, "jpeg")
#define MIME_SUFFIXES \
SUFFIX(Json , "json" , "JavaScript Object Notation") \
SUFFIX(Ber , "ber" , "Basic Encoding Rules") \
SUFFIX(Der , "der" , "Distinguished Encoding Rules") \
SUFFIX(Fastinfoset, "fastinfoset", "Fast Infoset") \
SUFFIX(Wbxml , "wbxml" , "WAP Binary XML") \
SUFFIX(Zip , "zip" , "ZIP file storage") \
SUFFIX(Xml , "xml" , "Extensible Markup Language")
enum
class
Type
{
#define TYPE(val, _) val,
MIME_TYPES
#undef TYPE
None
};
enum
class
Subtype
{
#define SUB_TYPE(val, _) val,
MIME_SUBTYPES
#undef SUB_TYPE
Vendor
,
Ext
,
None
};
enum
class
Suffix
{
#define SUFFIX(val, _, __) val,
MIME_SUFFIXES
#undef SUFFIX
None
,
Ext
};
// 3.9 Quality Values
class
Q
{
public:
// typedef uint8_t Type;
typedef
uint16_t
Type
;
explicit
Q
(
Type
val
)
{
if
(
val
>
100
)
{
throw
std
::
runtime_error
(
"Invalid quality value, must be in the [0; 100] range"
);
}
val_
=
val
;
}
static
Q
fromFloat
(
double
f
)
{
return
Q
(
static_cast
<
Type
>
(
f
*
100.0
));
}
Type
value
()
const
{
return
val_
;
}
operator
Type
()
const
{
return
val_
;
}
std
::
string
toString
()
const
;
private:
Type
val_
;
};
inline
bool
operator
==
(
Q
lhs
,
Q
rhs
)
{
return
lhs
.
value
()
==
rhs
.
value
();
}
// 3.7 Media Types
class
MediaType
{
public:
enum
Parse
{
DoParse
,
DontParse
};
MediaType
()
:
top_
(
Type
::
None
)
,
sub_
(
Subtype
::
None
)
,
suffix_
(
Suffix
::
None
)
{
}
MediaType
(
std
::
string
raw
,
Parse
parse
=
DontParse
)
:
top_
(
Type
::
None
)
,
sub_
(
Subtype
::
None
)
,
suffix_
(
Suffix
::
None
)
{
if
(
parse
==
DoParse
)
{
parseRaw
(
raw
.
c_str
(),
raw
.
length
());
}
else
{
raw_
=
std
::
move
(
raw
);
}
}
MediaType
(
Mime
::
Type
top
,
Mime
::
Subtype
sub
)
:
top_
(
top
)
,
sub_
(
sub
)
,
suffix_
(
Suffix
::
None
)
{
}
MediaType
(
Mime
::
Type
top
,
Mime
::
Subtype
sub
,
Mime
::
Suffix
suffix
)
:
top_
(
top
)
,
sub_
(
sub
)
,
suffix_
(
suffix
)
{
}
static
MediaType
fromRaw
(
const
char
*
str
,
size_t
len
);
static
MediaType
fromString
(
const
std
::
string
&
str
);
static
MediaType
fromString
(
std
::
string
&&
str
);
Mime
::
Type
top
()
const
{
return
top_
;
}
Mime
::
Subtype
sub
()
const
{
return
sub_
;
}
Mime
::
Suffix
suffix
()
const
{
return
suffix_
;
}
std
::
string
rawSub
()
const
{
return
rawSubIndex
.
splice
(
raw_
);
}
std
::
string
raw
()
const
{
return
raw_
;
}
const
Optional
<
Q
>&
q
()
const
{
return
q_
;
}
void
setQuality
(
Q
quality
);
Optional
<
std
::
string
>
getParam
(
std
::
string
name
)
const
;
void
setParam
(
std
::
string
name
,
std
::
string
value
);
std
::
string
toString
()
const
;
private:
void
parseRaw
(
const
char
*
str
,
size_t
len
);
Mime
::
Type
top_
;
Mime
::
Subtype
sub_
;
Mime
::
Suffix
suffix_
;
/* Let's save some extra memory allocations by only storing the
raw MediaType along with indexes of the relevant parts
Note: experimental for now as it might not be a good idea
*/
std
::
string
raw_
;
struct
Index
{
size_t
beg
;
size_t
end
;
std
::
string
splice
(
const
std
::
string
&
str
)
const
{
assert
(
end
>=
beg
);
return
str
.
substr
(
beg
,
end
-
beg
+
1
);
}
};
Index
rawSubIndex
;
Index
rawSuffixIndex
;
std
::
unordered_map
<
std
::
string
,
std
::
string
>
params
;
Optional
<
Q
>
q_
;
};
inline
bool
operator
==
(
const
MediaType
&
lhs
,
const
MediaType
&
rhs
)
{
return
lhs
.
top
()
==
rhs
.
top
()
&&
lhs
.
sub
()
==
rhs
.
sub
()
&&
lhs
.
suffix
()
==
rhs
.
suffix
();
}
}
// namespace Mime
}
// namespace Http
}
// namespace Net
#define MIME(top, sub) \
Net::Http::Mime::MediaType(Net::Http::Mime::Type::top, Net::Http::Mime::Subtype::sub)
#define MIME3(top, sub, suffix) \
Net::Http::Mime::MediaType(Net::Http::Mime::Type::top, Net::Http::Mime::Subtype::sub, Net::Http::Mime::Suffix::suffix);
tests/mime_test.cc
View file @
bb9909a2
#include "gtest/gtest.h"
#include "gtest/gtest.h"
#include "
http_header
.h"
#include "
mime
.h"
#include "http.h"
#include "http.h"
using
namespace
Net
::
Http
;
using
namespace
Net
::
Http
;
...
...
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