Remove dynamic exceptions
[anna.git] / source / http / Header.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <stdlib.h>
10
11 #include <anna/core/functions.hpp>
12
13 #include <anna/http/Header.hpp>
14 #include <anna/http/internal/Token.hpp>
15
16 using namespace std;
17 using namespace anna;
18
19 const char* http::Header::st_names [http::Header::Type::End] = {
20   "None",
21   "Cache-Control", "Connection", "Date", "Pragma", "Trailer", "Transfer-Encoding", "Upgrade", "Via",
22   "Warning",
23   "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Expect", "From",
24   "Host", "If-Match", "If-Modified-Since", "If-None-Match", "If-Range", "If-Unmodified-Since", "Max-Forwards",
25   "Proxy-Authorization", "Range", "Referer", "TE", "User-Agent",
26   "Allow", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5",
27   "Content-Range", "Content-Type", "Expires", "Last-Modified",
28   "Accept-Ranges", "Age", "ETAG", "Location", "Proxy-Authenticate", "Retry-After", "Server", "Vary",
29   "WWW-Authenticate", "Unknown"
30 };
31
32 http::Header* http::Header::initialize(const Type::_v type)
33 noexcept(false) {
34   if(type == Type::None || type >= Type::Unknown) {
35     string msg(asString());
36     msg += " | Type: ";
37     msg += functions::asString((int) type);
38     msg += " | Invalid header initializer";
39     throw RuntimeException(msg, ANNA_FILE_LOCATION);
40   }
41
42   a_type = type;
43
44   if(type >= Type::CacheControl && type <= Type::Warning)
45     a_category = Category::General;
46   else if(type >= Type::Accept && type <= Type::UserAgent)
47     a_category = Category::Request;
48   else if(type >= Type::Allow && type <= Type::LastModified)
49     a_category = Category::Entity;
50   else if(type >= Type::AcceptRanges && type <= Type::WWWAuthenticate)
51     a_category = Category::Response;
52   else
53     a_category = Category::Extension;
54
55   delete a_extensionName;
56   a_extensionName = NULL;
57   return this;
58 }
59
60 http::Header* http::Header::initialize(const string& name)
61 noexcept(false) {
62   if(a_extensionName == NULL)
63     a_extensionName = new string(name);
64   else
65     *a_extensionName = name;
66
67   a_type = Type::Unknown;
68   a_category = Category::Extension;
69   return this;
70 }
71
72 const int http::Header::getIntegerValue() const
73 {
74   return atoi(a_value.c_str());
75 }
76
77 void http::Header::setValue(const http::Token* token)
78 {
79   if(token == NULL)
80     a_value.clear();
81   else
82     a_value = token->getStringValue();
83 }
84
85 void http::Header::setValue(const int value)
86 {
87   a_value = anna::functions::asString(value);
88 }
89
90 http::Header& http::Header::operator = (const Header & other)
91 {
92   if(this == &other)
93     return *this;
94
95   a_type = other.a_type;
96   a_value = other.a_value;
97
98   if(other.a_extensionName == NULL) {
99     delete a_extensionName;
100     a_extensionName = NULL;
101   } else {
102     if(a_extensionName == NULL)
103       a_extensionName = new string(*other.a_extensionName);
104     else
105       *a_extensionName = *other.a_extensionName;
106   }
107
108   return *this;
109 }
110
111 int http::Header::compare(const char* str, const int flags) const
112 {
113   const char* p = a_value.c_str();
114   char* dup(NULL);
115   int result;
116
117   if(flags & Compare::LeftTrim) {
118     while(*p && *p == ' ')
119       p ++;
120   }
121
122   if((flags & Compare::RightTrim) && *p != 0 && anna_strchr(p, ' ') != NULL) {
123     char* ww;
124     ww = dup = strdup(p);
125     p = const_cast <const char*>(dup);
126     ww += anna_strlen(ww) - 1;
127
128     while(ww >= dup && *ww == ' ')
129       ww --;
130
131     *(ww + 1) = 0;
132   }
133
134   result = (flags & Compare::NoCase) ? strcasecmp(p, str) : anna_strcmp(p, str);
135
136   if(dup != NULL)
137     free(dup);
138
139   return result;
140 }
141
142 std::string http::Header::asString() const
143 {
144   string result("http::Header { Type: ");
145   result += asLiteral(a_type);
146
147   if(a_extensionName != NULL) {
148     result += " | Name: ";
149     result += *a_extensionName;
150   }
151
152   result += " | Value: ";
153
154   if(a_value.empty())
155     result += "<null>";
156   else
157     result += a_value;
158
159   return result += " }";
160 }
161
162 string http::Header::code() const
163 {
164   string result;
165
166   if(a_category == Category::Extension)
167     result = (a_extensionName == NULL) ? "None" : a_extensionName->c_str();
168   else
169     result = asLiteral(a_type);
170
171   if(a_value.length() > 0) {
172     result += ':';
173     result += a_value;
174   }
175
176   return result;
177 }
178
179 http::Header::Type::_v http::Header::asType(const http::Token* token)
180 {
181   for(int i = Type::Begin; token != NULL && i != Type::End; i ++) {
182     if(token->match(st_names [i]) == true)
183       return (Type::_v) i;
184   }
185
186   return Type::None;
187 }
188
189 const char* http::Header::asLiteral(const http::Header::Type::_v type)
190 {
191   return (type < Type::End) ? st_names [type] : "Extension";
192 }
193