1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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
17 // * Neither the name of the copyright holder 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.
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.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #include <anna/core/functions.hpp>
38 #include <anna/core/tracing/Logger.hpp>
40 #include <anna/http/parser/ReadHeader.hpp>
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>
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.
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.
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>.
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.
69 // (4) version 1.0.7 - Los header no reconocidos los guarda como extensiones.
70 //----------------------------------------------------------------------------------------------------
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);
80 const Tokenizer& tokenizer = transport.split(line, ':');
82 Tokenizer::const_iterator ii = tokenizer.begin();
84 const Token* token = tokenizer [ii];
86 const Header::Type::_v typeHeader = Header::asType(token);
88 Header* header = NULL;
90 if(typeHeader == Header::Type::None) {
92 string msg("http::parser::ReadHeader::processLine | Unreconized header identifier: ");
93 msg += line.getStringValue();
94 throw RuntimeException(msg, ANNA_FILE_LOCATION);
97 header = transport.getInputMessage()->createHeader(token->getStringValue());
98 } else if(typeHeader != Header::Type::TransferEncoding)
99 header = transport.getInputMessage()->createHeader(typeHeader);
101 token = tokenizer [++ ii]; // (1);
103 if(typeHeader == Header::Type::ContentLength) {
105 throw RuntimeException("http::parser::ReadHeader::processLine | Missing body length at Header ContentLength", ANNA_FILE_LOCATION);
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();
114 throw RuntimeException("http::parser::ReadHeader::processLine | Missing encode mode at Transfer-Encoding Header", ANNA_FILE_LOCATION);
116 if(token->match("chunked")) {
117 encodedBlock->setType(EncodedBlock::Type::Chunked);
118 setState(transport, ClassType::WaitChunkSize);
120 } else if(token != NULL) { // (2)
121 const int offset = token->calculeOffset(line);
122 const int size = line.getSize() - offset;
124 date.setValue(line.getData() + offset, size);
125 header->setValue(&date);
127 header->setValue(token); // (4)
129 if(header != NULL && Logger::isActive(Logger::Debug)) {
130 Logger::debug(header->asString(), ANNA_FILE_LOCATION);