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