Updated license
[anna.git] / source / http / parser / ReadHeader.cpp
1 // ANNA - Anna is Not Nothingness 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 <anna/core/functions.hpp>
38 #include <anna/core/tracing/Logger.hpp>
39
40 #include <anna/http/parser/ReadHeader.hpp>
41
42 #include <anna/http/Transport.hpp>
43 #include <anna/http/functions.hpp>
44 #include <anna/http/internal/defines.hpp>
45 #include <anna/http/Header.hpp>
46 #include <anna/http/internal/EncodedBlock.hpp>
47
48 using namespace std;
49 using namespace anna;
50
51 //----------------------------------------------------------------------------------------------------
52 // Si el mensaje HTTP no contiene la etiqueta content-length => el mensaje se acaba cuando llegue
53 // el primer crlf en solitario, es decir, la primera linea vacia.
54 //
55 // (1) El valor que acompania al Header es opcional ... solo verificamos que venga en el caso de
56 // que sea el ContentLength.
57 // (2) Hay una probabilidad muy alta de que la fecha contenga algun ':' asi que hay que tratarlo
58 //     de forma distinta al resto de los header.
59 //
60 // Recordar que el ContentLength indica la longitud del cuerpo del mensaje (si existe) =>
61 // la longitud total del mensaje sea <la longitud de la cabecera> + <longitud del body>.
62 //
63 // (3) version 1.0.5 - El servidor de aplicaciones tomcat envia mensajes HTTP sin el Header Content-Length, con lo que
64 // aplicando la regla de la RFC siempre obtendremos un cuerpo de mensaje vacio.
65 // Segun la RFC cuando no llega este indicador el mensaje termina con los primeros 0xd0xa consecutivos.
66 // Para permitir la interconexion de nuestros sistemas con este servidor de aplicaciones, vamos a modificar el comportamiento
67 // del parser y considerando el fin del mensaje el fin del paquete recibido como parametro.
68 //
69 // (4) version 1.0.7 - Los header no reconocidos los guarda como extensiones.
70 //----------------------------------------------------------------------------------------------------
71 /*virtual*/
72 int http::parser::ReadHeader::processLine(http::Transport& transport, const DataBlock& dataBlock, const http::Token& line) const
73 throw(RuntimeException) {
74   if(line.getSize() == 0) {                                                  // (3)
75     const int size = line.calculeOffset(dataBlock) + sizeEndOfLine;
76     setState(transport, ClassType::WaitMessage);
77     return size;
78   }
79
80   const Tokenizer& tokenizer = transport.split(line, ':');
81
82   Tokenizer::const_iterator ii = tokenizer.begin();
83
84   const Token* token = tokenizer [ii];
85
86   const Header::Type::_v typeHeader = Header::asType(token);
87
88   Header* header = NULL;
89
90   if(typeHeader == Header::Type::None) {
91     if(token == NULL) {
92       string msg("http::parser::ReadHeader::processLine | Unreconized header identifier: ");
93       msg += line.getStringValue();
94       throw RuntimeException(msg, ANNA_FILE_LOCATION);
95     }
96
97     header = transport.getInputMessage()->createHeader(token->getStringValue());
98   } else if(typeHeader != Header::Type::TransferEncoding)
99     header = transport.getInputMessage()->createHeader(typeHeader);
100
101   token = tokenizer [++ ii];                                                            // (1);
102
103   if(typeHeader == Header::Type::ContentLength) {
104     if(token == NULL)
105       throw RuntimeException("http::parser::ReadHeader::processLine | Missing body length at Header ContentLength", ANNA_FILE_LOCATION);
106
107     transport.setContentLength(token->getIntegerValue());
108     header->setValue(token);
109     setState(transport, ClassType::WaitEndOfHeader);
110   } else if(typeHeader == Header::Type::TransferEncoding) {
111     EncodedBlock* encodedBlock = transport.getEncodedBlock();
112
113     if(token == NULL)
114       throw RuntimeException("http::parser::ReadHeader::processLine | Missing encode mode at Transfer-Encoding Header", ANNA_FILE_LOCATION);
115
116     if(token->match("chunked")) {
117       encodedBlock->setType(EncodedBlock::Type::Chunked);
118       setState(transport, ClassType::WaitChunkSize);
119     }
120   } else if(token != NULL)  {                         // (2)
121     const int offset = token->calculeOffset(line);
122     const int size = line.getSize() - offset;
123     Token date;
124     date.setValue(line.getData() + offset, size);
125     header->setValue(&date);
126   } else
127     header->setValue(token);                                          // (4)
128
129   if(header != NULL && Logger::isActive(Logger::Debug)) {
130     Logger::debug(header->asString(), ANNA_FILE_LOCATION);
131   }
132
133   return -1;
134 }
135