Commit 9ee9db90 authored by Mathieu STEFANI's avatar Mathieu STEFANI

Added MIME/MediaType types and parsing. Headers constructors are also now explicit

parent 0329db6a
......@@ -15,8 +15,9 @@ class MyHandler : public Net::Http::Handler {
using namespace Net::Http;
Net::Http::Response response(Net::Http::Code::Ok, "PONG");
// response.headers
// .add(std::make_shared<Server>("lys"));
response.headers
.add(std::make_shared<Server>("lys"))
.add(std::make_shared<ContentType>(MIME(Text, Plain)));
response.writeTo(peer);
}
......
......@@ -143,9 +143,6 @@ namespace Private {
else if (tryMatch("DELETE")) {
request->method = Method::Delete;
}
else {
raise("Lol wat");
}
auto n = cursor.next();
if (n == Cursor::Eof) return State::Again;
......
......@@ -8,6 +8,8 @@
#include "common.h"
#include <stdexcept>
#include <iterator>
#include <cstring>
#include <iostream>
using namespace std;
......@@ -15,6 +17,150 @@ namespace Net {
namespace Http {
namespace Mime {
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;
// HUGE @Todo: Validate the input when parsing to avoid overflow
// Parse type
const char *p = strchr(str, '/');
if (p == NULL) return res;
const ptrdiff_t size = p - str;
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 (strncmp(str, s, size) == 0) { \
top = Type::val; \
break; \
}
MIME_TYPES
#undef TYPE
else {
top = Type::Ext;
}
} while (0);
if (top == Type::Ext) return res;
res.top = top;
// Parse subtype
Mime::Subtype sub;
++p;
do {
#define SUB_TYPE(val, s) \
if (strncmp(p, s, sizeof (s) - 1) == 0) { \
sub = Subtype::val; \
p += sizeof(s) - 1; \
break; \
}
MIME_SUBTYPES
#undef SUB_TYPE
else {
sub = Subtype::Ext;
}
} while (0);
if (sub == Subtype::Ext) return res;
res.sub = sub;
// Parse suffix
Mime::Suffix suffix = Suffix::None;
if (*p == '+') {
++p;
do {
#define SUFFIX(val, s, _) \
if (strncmp(p, s, sizeof (s) - 1) == 0) { \
suffix = Suffix::val; \
break; \
}
MIME_SUFFIXES
#undef SUFFIX
else {
suffix = Suffix::Ext;
}
} while (0);
res.suffix = suffix;
}
return res;
}
std::string
MediaType::toString() const {
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
}
};
std::string res;
res += topString(top);
res += "/";
res += subString(sub);
if (suffix != Suffix::None) {
res += suffixString(suffix);
}
return res;
}
} // namespace Mime
const char* encodingString(Encoding encoding) {
switch (encoding) {
case Encoding::Gzip:
......@@ -154,6 +300,17 @@ Server::write(std::ostream& os) const
std::ostream_iterator<std::string>(os, " "));
}
void
ContentType::parseRaw(const char* str, size_t len)
{
}
void
ContentType::write(std::ostream& os) const {
os << "Content-Type: ";
os << mime_.toString();
}
} // namespace Http
} // namespace Net
......@@ -61,6 +61,113 @@ enum class 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
Ext
};
enum class Subtype {
#define SUB_TYPE(val, _) val,
MIME_SUBTYPES
#undef SUB_TYPE
Ext
};
enum class Suffix {
#define SUFFIX(val, _, __) val,
MIME_SUFFIXES
#undef SUFFIX
None,
Ext
};
// 3.7 Media Types
class MediaType {
public:
constexpr MediaType()
: top(Type::Ext)
, sub(Subtype::Ext)
, suffix(Suffix::None)
{ }
constexpr MediaType(Mime::Type top, Mime::Subtype sub)
: top(top)
, sub(sub)
, suffix(Suffix::None)
{ }
constexpr MediaType(Mime::Type top, Mime::Subtype sub, Mime::Suffix suffix)
: top(top)
, sub(sub)
, suffix(suffix)
{ }
Mime::Type top;
Mime::Subtype sub;
Mime::Suffix suffix;
static MediaType fromRaw(const char* str, size_t len);
static MediaType fromString(const std::string& str);
static MediaType fromString(std::string&& str);
std::string toString() const;
};
inline bool operator==(const MediaType& lhs, const MediaType& rhs) {
return lhs.top == rhs.top && lhs.sub == rhs.sub;
}
} // 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 {
public:
virtual const char *name() const = 0;
......@@ -115,7 +222,7 @@ public:
: value_(0)
{ }
ContentLength(uint64_t val)
explicit ContentLength(uint64_t val)
: value_(val)
{ }
......@@ -137,7 +244,7 @@ public:
, port_(-1)
{ }
Host(const std::string& host, int16_t port = -1)
explicit Host(const std::string& host, int16_t port = -1)
: host_(host)
, port_(port)
{ }
......@@ -158,7 +265,7 @@ public:
NAME("User-Agent")
UserAgent() { }
UserAgent(const std::string& ua) :
explicit UserAgent(const std::string& ua) :
ua_(ua)
{ }
......@@ -192,7 +299,7 @@ public:
: encoding_(Encoding::Identity)
{ }
ContentEncoding(Encoding encoding)
explicit ContentEncoding(Encoding encoding)
: encoding_(encoding)
{ }
......@@ -211,9 +318,9 @@ public:
Server() { }
Server(const std::vector<std::string>& tokens);
Server(const std::string& token);
Server(const char* token);
explicit Server(const std::vector<std::string>& tokens);
explicit Server(const std::string& token);
explicit Server(const char* token);
void parse(const std::string& data);
void write(std::ostream& os) const;
......@@ -223,6 +330,26 @@ private:
std::vector<std::string> tokens_;
};
class ContentType : public Header {
public:
NAME("Content-Type")
ContentType() { }
explicit ContentType(const Mime::MediaType& mime) :
mime_(mime)
{ }
void parseRaw(const char* str, size_t len);
void write(std::ostream& os) const;
Mime::MediaType mime() const { return mime_; }
private:
Mime::MediaType mime_;
};
} // namespace Http
} // namespace Net
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment