Spinning Topp Logo BlackTopp Studios
inc
httpmessage.cpp
1 // © Copyright 2010 - 2015 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 
41 #ifndef _networkhttpmessage_cpp
42 #define _networkhttpmessage_cpp
43 
44 #include "Network/httpmessage.h"
45 
46 #include "stringtool.h"
47 
48 namespace
49 {
50  /// @internal
51  /// @brief Convenience String for Header Field returns that fail.
52  const Mezzanine::String BlankStr = "";
53 
54  /*
55  /// @brief A comparison method between individual chars that is case-insensitive.
56  /// @param First The first char to be compared.
57  /// @param Second The second char to be compared.
58  /// @return Returns true if the first char is less than the second char when disregarding case.
59  Mezzanine::Boole LowerCaseCompare(const Mezzanine::Char8 First, const Mezzanine::Char8 Second)
60  { return ( tolower(First) < tolower(Second) ); }
61 
62  /// @brief A comparison method that will compare the names of HeaderFields lexicographically in a case-insensitive way.
63  /// @param First The first HeaderField to be compared.
64  /// @param Second The second HeaderField to be compared.
65  /// @return Returns true if the First HeaderField is less than the Second HeaderField.
66  Mezzanine::Boole HeaderFieldCompare(const Mezzanine::Network::HeaderField& First, const Mezzanine::Network::HeaderField& Second)
67  { return std::lexicographical_compare(First.HeaderName.begin(),First.HeaderName.end(),Second.HeaderName.begin(),Second.HeaderName.end(),LowerCaseCompare); }
68  // */
69 
70  /// @brief Compares two Strings to see if they are equal in a case-insensitive way.
71  /// @param First The first String to be compared.
72  /// @param Second The second String to be compared.
73  /// @return Returns true if the two Strings are equal when not counting casing, false otherwise.
74  Mezzanine::Boole IsEqualCaseInsensitive(const Mezzanine::String& First, const Mezzanine::String& Second)
75  {
76  if( First.size() != Second.size() ) {
77  return false;
78  }
79 
80  for( Mezzanine::Whole Index = 0 ; Index < First.size() ; ++Index )
81  {
82  if( tolower( First[Index] ) != tolower( Second[Index] ) ) {
83  return false;
84  }
85  }
86 
87  return true;
88  }
89 }
90 
91 namespace Mezzanine
92 {
93  namespace Network
94  {
96  MaxHeaderFields(100),
97  MessageVersion(1,0)
98  { }
99 
100  HTTPMessage::HTTPMessage(const UInt16 VerMajor, const UInt16 VerMinor) :
101  MaxHeaderFields(100),
102  MessageVersion(VerMajor,VerMinor)
103  { }
104 
106  MaxHeaderFields(100),
107  MessageVersion(Version)
108  { }
109 
111  { }
112 
114  {
115  if( ToParse.length() == 8 &&
116  ToParse.at(6) == '.' &&
117  StringTools::StartsWith( ToParse, "http/", false ) )
118  {
119  this->MessageVersion.Major = static_cast<UInt16>( ToParse.at(5) - '0' );
120  this->MessageVersion.Minor = static_cast<UInt16>( ToParse.at(7) - '0' );
121  return true;
122  }
123  return false;
124  }
125 
127  {
128  this->RemoveAllFields();
129  Boole PreColon = true;
130  String FieldName;
131  String FieldValue;
132  while( CurrIt != EndIt && this->MessageFields.size() < this->MaxHeaderFields )
133  {
134  switch( *CurrIt )
135  {
136  case '\r':
137  {
138  // Just skip
139  break;
140  }
141  case '\n':
142  {
143  PreColon = true;
144  //StringTools::ToLowerCase(FieldName);
145  StringTools::Trim(FieldName,true,true);
146  StringTools::Trim(FieldValue,true,true);
147  this->SetField(FieldName,FieldValue);
148  FieldName.clear();
149  FieldValue.clear();
150  if( *(CurrIt + 1) == '\r' && *(CurrIt + 2) == '\n' ) {
151  CurrIt += 3;
152  return true;
153  }
154  break;
155  }
156  case ':':
157  {
158  if( PreColon ) {
159  PreColon = false;
160  }else{
161  FieldValue.push_back( *CurrIt );
162  }
163  break;
164  }
165  default:
166  {
167  if( PreColon ) FieldName.push_back( *CurrIt );
168  else FieldValue.push_back( *CurrIt );
169  break;
170  }
171  }
172  ++CurrIt;
173  }
174  return false;
175  }
176 
178  {
179  while( (*CurrIt) != ' ' && (*CurrIt) != '\r' && CurrIt != EndIt )
180  {
181  Component.push_back( *CurrIt );
182  ++CurrIt;
183  }
184  Boole EoL = false;
185  if( CurrIt != EndIt ) {
186  // Increment passed the end of the line if we're there. Or just increment into the next space valid character if we're on a space.
187  if( (*CurrIt) == '\r' && *(CurrIt + 1) == '\n' ) {
188  EoL = true;
189  CurrIt += 2;
190  }else if( (*CurrIt) == ' ' ) {
191  ++CurrIt;
192  }
193  }
194  return EoL;
195  }
196 
198  {
199  while( CurrIt != EndIt )
200  {
201  ++CurrIt;
202  if( (*CurrIt) == '\n' ) {
203  ++CurrIt;
204  break;
205  }
206  }
207  }
208 
209  ///////////////////////////////////////////////////////////////////////////////
210  // Core Operations
211 
212  ///////////////////////////////////////////////////////////////////////////////
213  // Utility
214 
216  { this->MessageVersion = Version; }
217 
219  { return this->MessageVersion; }
220 
221  void HTTPMessage::SetHTTPVersion(const UInt16 Major, const UInt16 Minor)
222  { this->MessageVersion.Major = Major; this->MessageVersion.Minor = Minor; }
223 
225  { this->MessageVersion.Major = Major; }
226 
228  { return this->MessageVersion.Major; }
229 
231  { this->MessageVersion.Minor = Minor; }
232 
234  { return this->MessageVersion.Minor; }
235 
236  void HTTPMessage::SetBody(const String& Body)
237  { this->MessageBody = Body; }
238 
240  { return this->MessageBody; }
241 
242  void HTTPMessage::SetMaxFields(const Whole MaxFields)
243  { this->MaxHeaderFields = MaxFields; }
244 
246  { return this->MaxHeaderFields; }
247 
248  void HTTPMessage::SetField(const String& FieldName, const String& FieldValue)
249  {
250  // Code for using std::map
251  /*this->MessageFields[ StringTools::LowerCaseCopy(FieldName) ] = FieldValue;// */
252 
253  for( HeaderFieldIterator FieldIt = this->MessageFields.begin() ; FieldIt != this->MessageFields.end() ; ++FieldIt )
254  {
255  if( IsEqualCaseInsensitive( (*FieldIt).HeaderName, FieldName ) ) {
256  (*FieldIt).HeaderValue = FieldValue;
257  return;
258  }
259  }
260  this->MessageFields.push_back( HeaderField(FieldName,FieldValue) );
261  }
262 
263  const String& HTTPMessage::GetField(const String& FieldName) const
264  {
265  // Code for using std::map
266  /*NameValuePairMap::const_iterator FieldIt = this->MessageFields.find( StringTools::LowerCaseCopy(FieldName) );
267  if( FieldIt != this->MessageFields.end() ) {
268  return (*FieldIt).second;
269  }
270  return BlankStr;// */
271 
272  for( ConstHeaderFieldIterator FieldIt = this->MessageFields.begin() ; FieldIt != this->MessageFields.end() ; ++FieldIt )
273  {
274  if( IsEqualCaseInsensitive( (*FieldIt).HeaderName, FieldName ) ) {
275  return (*FieldIt).HeaderValue;
276  }
277  }
278  return BlankStr;
279  }
280 
281  Boole HTTPMessage::HasField(const String& FieldName) const
282  {
283  // Code for using std::map
284  /*NameValuePairMap::const_iterator FieldIt = this->MessageFields.find( StringTools::LowerCaseCopy(FieldName) );
285  return ( FieldIt != this->MessageFields.end() );// */
286 
287  for( ConstHeaderFieldIterator FieldIt = this->MessageFields.begin() ; FieldIt != this->MessageFields.end() ; ++FieldIt )
288  {
289  if( IsEqualCaseInsensitive( (*FieldIt).HeaderName, FieldName ) ) {
290  return true;
291  }
292  }
293  return false;
294  }
295 
296  void HTTPMessage::RemoveField(const String& FieldName)
297  {
298  // Code for using std::map
299  /*NameValuePairMap::iterator FieldIt = this->MessageFields.find( StringTools::LowerCaseCopy(FieldName) );
300  if( FieldIt != this->MessageFields.end() ) {
301  this->MessageFields.erase(FieldIt);
302  }// */
303 
304  for( HeaderFieldIterator FieldIt = this->MessageFields.begin() ; FieldIt != this->MessageFields.end() ; ++FieldIt )
305  {
306  if( IsEqualCaseInsensitive( (*FieldIt).HeaderName, FieldName ) ) {
307  this->MessageFields.erase(FieldIt);
308  return;
309  }
310  }
311  }
312 
314  {
315  this->MessageFields.clear();
316  }
317 
318  ///////////////////////////////////////////////////////////////////////////////
319  // Recommended Header Field Convenience Methods
320 
322  { this->SetField("Connection",Connection); }
323 
325  { return this->GetField("Connection"); }
326 
327  void HTTPMessage::SetContentLengthHeader(const String& ContentLength)
328  { this->SetField("Content-Length",ContentLength); }
329 
331  { return this->GetField("Content-Length"); }
332 
333  void HTTPMessage::SetContentTypeHeader(const String& ContentType)
334  { this->SetField("Content-Type",ContentType); }
335 
337  { return this->GetField("Content-Type"); }
338  }//Network
339 }//Mezzanine
340 
341 #endif
Boole StartsWith(const String &Str, const String &Pattern, const Boole CaseSensitive)
Checks a String to see if it starts with a specific pattern.
Definition: stringtool.cpp:227
A base class for the state of a connection made between peers.
Definition: connection.h:56
String::const_iterator StringIterator
Convenience typedef for String iterators.
Definition: httpmessage.h:77
Boole HasField(const String &FieldName) const
Checks if this message has the named header field.
void RemoveField(const String &FieldName)
Removes a specific field from this message by name.
Boole ParseHTTPFields(StringIterator &CurrIt, const StringIterator EndIt)
Parses the HTTP fields from a provided string.
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
const String & GetConnectionHeader() const
Gets the Connection Header.
UInt16 GetHTTPMinorVersion() const
Gets the minor version of this message.
UInt16 Major
The Major component of the version to be expressed.
Definition: version.h:68
const String & GetContentTypeHeader() const
Gets the Content-Type Header.
void Trim(String &Source, Boole Left, Boole Right)
Trims all whitespaces and tabs from a one or both sides of a String.
Definition: stringtool.cpp:128
const String & GetField(const String &FieldName) const
Gets a Name-Value pair for a header field in the message.
virtual ~HTTPMessage()
Class destructor.
void RemoveAllFields()
Removes every field from this message.
const SimpleVersion & GetHTTPVersion() const
Gets both the major and minor version of this message.
SimpleVersion MessageVersion
The version component for this response.
Definition: httpmessage.h:90
UInt16 Minor
The Minor component of the version to be expressed.
Definition: version.h:70
uint16_t UInt16
An 16-bit unsigned integer.
Definition: datatypes.h:122
void SetContentLengthHeader(const String &ContentLength)
Sets the Content-Length Header.
Boole GetMessageComponent(StringIterator &CurrIt, const StringIterator EndIt, String &Component)
Extracts all characters from CurrIt until the first space encountered or EndIt, whichever comes first...
void SetBody(const String &Body)
Sets the message body containing additional information.
HeaderFieldContainer::const_iterator ConstHeaderFieldIterator
Const Iterator type for Header Fields in this class.
Definition: httpmessage.h:83
A very basic class for expressing an API or syntax version.
Definition: version.h:53
const String & GetContentLengthHeader() const
Gets the Content-Length Header.
UInt16 GetHTTPMajorVersion() const
Gets the major version of this message.
void SetField(const String &FieldName, const String &FieldValue)
Sets a Name-Value pair for a header field in the message.
Whole GetMaxFields() const
Gets how many header fields can be added to this message during parsing.
void SetHTTPVersion(const SimpleVersion &Version)
Sets both the major and minor version of this message via SimpleVersion.
Whole MaxHeaderFields
The maximum number of allowed header fields in this message.
Definition: httpmessage.h:87
Convenience class for storing Header fields in internet messaging protocols.
Definition: httpmessage.h:54
void SetConnectionHeader(const String &Connection)
Sets the Connection Header.
Boole ParseHTTPVersion(const String &ToParse)
Parses the HTTP version from a provided string.
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
HeaderFieldContainer MessageFields
A container of fields to populate the message header with.
Definition: httpmessage.h:96
void SetMaxFields(const Whole MaxFields)
Sets how many header fields can be added to this message during parsing.
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
String MessageBody
The body of the message.
Definition: httpmessage.h:93
HeaderFieldContainer::iterator HeaderFieldIterator
Iterator type for Header Fields in this class.
Definition: httpmessage.h:81
void SetHTTPMinorVersion(const UInt16 Minor)
Sets the minor version of this message.
void SetContentTypeHeader(const String &ContentType)
Sets the Content-Type Header.
const String & GetBody() const
Gets the message body containing additional information.
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
void SetHTTPMajorVersion(const UInt16 Major)
Sets the major version of this message.
void AdvanceToNewline(StringIterator &CurrIt, const StringIterator EndIt)
Convenience method that will ignore and advance passed all characters until one passed the first newl...
HTTPMessage()
Blank Constructor.
Definition: httpmessage.cpp:95