First commit
[anna.git] / source / http / Header.cpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <stdlib.h>
38
39 #include <anna/core/functions.hpp>
40
41 #include <anna/http/Header.hpp>
42 #include <anna/http/internal/Token.hpp>
43
44 using namespace std;
45 using namespace anna;
46
47 const char* http::Header::st_names [http::Header::Type::End] = {
48   "None",
49   "Cache-Control", "Connection", "Date", "Pragma", "Trailer", "Transfer-Encoding", "Upgrade", "Via",
50   "Warning",
51   "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Expect", "From",
52   "Host", "If-Match", "If-Modified-Since", "If-None-Match", "If-Range", "If-Unmodified-Since", "Max-Forwards",
53   "Proxy-Authorization", "Range", "Referer", "TE", "User-Agent",
54   "Allow", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5",
55   "Content-Range", "Content-Type", "Expires", "Last-Modified",
56   "Accept-Ranges", "Age", "ETAG", "Location", "Proxy-Authenticate", "Retry-After", "Server", "Vary",
57   "WWW-Authenticate", "Unknown"
58 };
59
60 http::Header* http::Header::initialize(const Type::_v type)
61 throw(RuntimeException) {
62   if(type == Type::None || type >= Type::Unknown) {
63     string msg(asString());
64     msg += " | Type: ";
65     msg += functions::asString((int) type);
66     msg += " | Invalid header initializer";
67     throw RuntimeException(msg, ANNA_FILE_LOCATION);
68   }
69
70   a_type = type;
71
72   if(type >= Type::CacheControl && type <= Type::Warning)
73     a_category = Category::General;
74   else if(type >= Type::Accept && type <= Type::UserAgent)
75     a_category = Category::Request;
76   else if(type >= Type::Allow && type <= Type::LastModified)
77     a_category = Category::Entity;
78   else if(type >= Type::AcceptRanges && type <= Type::WWWAuthenticate)
79     a_category = Category::Response;
80   else
81     a_category = Category::Extension;
82
83   delete a_extensionName;
84   a_extensionName = NULL;
85   return this;
86 }
87
88 http::Header* http::Header::initialize(const string& name)
89 throw(RuntimeException) {
90   if(a_extensionName == NULL)
91     a_extensionName = new string(name);
92   else
93     *a_extensionName = name;
94
95   a_type = Type::Unknown;
96   a_category = Category::Extension;
97   return this;
98 }
99
100 const int http::Header::getIntegerValue() const
101 throw() {
102   return atoi(a_value.c_str());
103 }
104
105 void http::Header::setValue(const http::Token* token)
106 throw() {
107   if(token == NULL)
108     a_value.clear();
109   else
110     a_value = token->getStringValue();
111 }
112
113 void http::Header::setValue(const int value)
114 throw() {
115   a_value = anna::functions::asString(value);
116 }
117
118 http::Header& http::Header::operator = (const Header & other)
119 throw() {
120   if(this == &other)
121     return *this;
122
123   a_type = other.a_type;
124   a_value = other.a_value;
125
126   if(other.a_extensionName == NULL) {
127     delete a_extensionName;
128     a_extensionName = NULL;
129   } else {
130     if(a_extensionName == NULL)
131       a_extensionName = new string(*other.a_extensionName);
132     else
133       *a_extensionName = *other.a_extensionName;
134   }
135
136   return *this;
137 }
138
139 int http::Header::compare(const char* str, const int flags) const
140 throw() {
141   const char* p = a_value.c_str();
142   char* dup(NULL);
143   int result;
144
145   if(flags & Compare::LeftTrim) {
146     while(*p && *p == ' ')
147       p ++;
148   }
149
150   if((flags & Compare::RightTrim) && *p != 0 && anna_strchr(p, ' ') != NULL) {
151     char* ww;
152     ww = dup = strdup(p);
153     p = const_cast <const char*>(dup);
154     ww += anna_strlen(ww) - 1;
155
156     while(ww >= dup && *ww == ' ')
157       ww --;
158
159     *(ww + 1) = 0;
160   }
161
162   result = (flags & Compare::NoCase) ? strcasecmp(p, str) : anna_strcmp(p, str);
163
164   if(dup != NULL)
165     free(dup);
166
167   return result;
168 }
169
170 std::string http::Header::asString() const
171 throw() {
172   string result("http::Header { Type: ");
173   result += asLiteral(a_type);
174
175   if(a_extensionName != NULL) {
176     result += " | Name: ";
177     result += *a_extensionName;
178   }
179
180   result += " | Value: ";
181
182   if(a_value.empty())
183     result += "<null>";
184   else
185     result += a_value;
186
187   return result += " }";
188 }
189
190 string http::Header::code() const
191 throw() {
192   string result;
193
194   if(a_category == Category::Extension)
195     result = (a_extensionName == NULL) ? "None" : a_extensionName->c_str();
196   else
197     result = asLiteral(a_type);
198
199   if(a_value.length() > 0) {
200     result += ':';
201     result += a_value;
202   }
203
204   return result;
205 }
206
207 http::Header::Type::_v http::Header::asType(const http::Token* token)
208 throw() {
209   for(int i = Type::Begin; token != NULL && i != Type::End; i ++) {
210     if(token->match(st_names [i]) == true)
211       return (Type::_v) i;
212   }
213
214   return Type::None;
215 }
216
217 const char* http::Header::asLiteral(const http::Header::Type::_v type)
218 throw() {
219   return (type < Type::End) ? st_names [type] : "Extension";
220 }
221