diff --git a/doc/HTTP_CNL113796_PRI.doc b/doc/HTTP_CNL113796_PRI.doc index ea6ebe8b5c2633e7652a5be21631a4985a1568b6..60a78a3294fffc1449c8ed33b46c62376be391de 100644 Binary files a/doc/HTTP_CNL113796_PRI.doc and b/doc/HTTP_CNL113796_PRI.doc differ diff --git a/src/HTTP_EncDec.cc b/src/HTTP_EncDec.cc index f3854206e1a0ba846c56a723ddec4fcbe8088340..7de835b6e69ac2dcd51d1ba457c29cd8646c32a2 100644 --- a/src/HTTP_EncDec.cc +++ b/src/HTTP_EncDec.cc @@ -9,7 +9,7 @@ ******************************************************************************/ // // File: HTTP_EncDec.cc -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se // Reference: RFC7230 - RFC7235 diff --git a/src/HTTP_MessageLen.ttcn b/src/HTTP_MessageLen.ttcn index c983c7a97c1bc7251795ac26fdce32ffd766566c..088f35793d3f16d6d978520dce5eef4f7b870e94 100644 --- a/src/HTTP_MessageLen.ttcn +++ b/src/HTTP_MessageLen.ttcn @@ -6,14 +6,18 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: +* Eduard Czimbalmos * Eszter Susanszky ******************************************************************************/ // // File: HTTP_MessageLen.ttcn -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se module HTTP_MessageLen { external function ef_HTTPMessage_len(in octetstring pl_stream) return integer + external function ef_HTTPMessage_len_forConnectResp(in octetstring pl_stream) return integer + external function ef_HTTPMessage_len_forHeadResp(in octetstring pl_stream) return integer + external function ef_HTTPMessage_len_forConnClosed(in octetstring pl_stream) return integer } diff --git a/src/HTTP_MessageLen_Function.cc b/src/HTTP_MessageLen_Function.cc index 0921f06ecc4da19f23c9fe6818da60df102fe01e..2e6d25268f3ab8cc277667e5204da115102f5f6e 100644 --- a/src/HTTP_MessageLen_Function.cc +++ b/src/HTTP_MessageLen_Function.cc @@ -1,148 +1,204 @@ /****************************************************************************** -* Copyright (c) 2015 Ericsson AB +* Copyright (c) 2016 Ericsson AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: +* Eduard Czimbalmos * Eszter Susanszky ******************************************************************************/ // // File: HTTP_MessageLen_Function.cc -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se #include "HTTP_Types.hh" #include "HTTP_MessageLen.hh" -//#include <stdlib.h> +#include <string> +#include <stdio.h> +#include <strings.h> +#include <ctype.h> + using namespace HTTP__Types; namespace HTTP__MessageLen { - + enum ReqResp {request, response, def}; enum Transfer_Encoding {chunked, notchunked, none}; + + // return the length of the first line in the buffer including the \r\n + // So 2 is returned for empty line + // -1 if there is no \r\n in the buffer + // handles the line folding if needed + + int get_http_line(const char *buff, int length, bool folding=false){ + int ret_val=0; // store the length of the line + bool end_found=false; // is the line ending found? + while(length>0){ + ret_val++; + length--; + if(*buff == '\n'){ + if( !folding || !((length>0) && (buff[1] == ' ' || buff[1] == '\t')) ){ // not line folding. ie the \n is not followed with space or tab + end_found=true; // this is the end of the line + break; + } + } + buff++; + } + return end_found?ret_val:-1; + } - INTEGER ef__HTTPMessage__len(const OCTETSTRING& pl__stream) + INTEGER f_HTTPMessage_len_common( + const OCTETSTRING& pl__stream, + const boolean connClosed, + const boolean head_req, + const boolean connect_req) { int stream_length = pl__stream.lengthof(); - if(stream_length < 0) return -1; - - int content_length = 0; - int end_of_startline = 0; - int end_of_headers = 0; - int end_of_te = 0; - int end_of_msg = 0; - int end_of_chunklngth = 0; - - ReqResp reqresp = def; - Transfer_Encoding te = none; + if(stream_length < 16) return -1; + // The smallest syntatically correct HTTP message is: + // A / HTTP/0.0\r\n\r\n + // Which is 16 octet - const unsigned char* streamptr = pl__stream; - const unsigned char* ptr = pl__stream; - const CHARSTRING crlf = "\r\n"; - const CHARSTRING crlfcrlf = "\r\n\r\n"; + const char *stream=(const char *)(const unsigned char *)pl__stream; + int line_length=-1; + int resp_code=0; + bool is_request=false; + bool is_chunked=false; + int content_length=-1; - // go to the end of stream, stop if end of startline found - while(ptr-streamptr + 2 <= stream_length && end_of_startline == 0) - { - if(memcmp(ptr, (const char*)crlf, 2) == 0) end_of_startline = 1; - else ptr++; + // skeep leading /r/n + // there should'n be any but be conservative + while((line_length=get_http_line(stream,stream_length))==2){ + stream+=line_length; + stream_length-=line_length; } - - // startline hasn't arrived - if(end_of_startline == 0) return -1; - else ptr += 2; - - //check if request or response - if(memcmp(streamptr, "HTTP/", 5) == 0 ) reqresp = response; else reqresp = request; - - // \r\n\r\n -> empty header list, return -1 - if(memcmp(ptr, (const char*)crlf, 2) == 0 ) return -1; - - while(ptr-streamptr + 4 <= stream_length && end_of_headers == 0) + if(line_length==-1){ // there is no whole line in the buffer + return -1; + } + // parse the header line { - if(memcmp(ptr, (const char*)crlfcrlf, 4) == 0 ) {end_of_headers = 1;} - else - { - if(ptr-streamptr + 15 <= stream_length && strncasecmp((const char*)ptr, "Content-Length:", 15) == 0) - { - ptr+= 15; - content_length = (int)strtol((const char*)ptr, NULL, 10); - } else if(ptr-streamptr + 18 <= stream_length && strncasecmp((const char*)ptr, "Transfer-Encoding:", 18) == 0) - { - te = notchunked; - ptr += 18; - - while(end_of_te == 0) - { - if(ptr-streamptr + 2 <= stream_length && memcmp(ptr, (const char*)crlf, 2) == 0 ) {end_of_te = 1; ptr += 2;} - else if(ptr-streamptr + 9 <= stream_length && !strncasecmp((const char*)ptr, "chunked\r\n", 9)) {te = chunked; end_of_te = 1; ptr += 9;} //chunked/r/n (last encoding is chunked) - else { ptr++; } - } - - if(end_of_te == 0) return -1; - } else ptr++; + std::string str(stream,line_length); + if(sscanf(str.c_str(),"HTTP/%*d.%*d %d ",&resp_code)==1){ + // response received + is_request=false; + } else { + // it should be a request + is_request=true; } } + stream+=line_length; + stream_length-=line_length; + + // search for the end of the headers + while((line_length=get_http_line(stream,stream_length,true))!=2){ + if(line_length==-1){ // there is no whole line in the buffer + return -1; + } + // check for specific headers + // Content-Length + if((line_length>17) && (strncasecmp(stream, "Content-Length:", 15) == 0) ){ // the minimum length of the Content-Length is 18: 15 (Content-Length:) + at least 1 digit + crlf + content_length = (int)strtol(stream+15, NULL, 10); + } + if((line_length>26) && (strncasecmp(stream, "Transfer-Encoding:", 18) == 0) ){ // the minimum length 27: 18 (Transfer-Encoding:) + 7 (chunked) + crlf + std::string str(stream+18,line_length-18); // just the data part + if(str.find("chunked")!=std::string::npos){ + is_chunked=true; + } + } + stream+=line_length; + stream_length-=line_length; + } - if(end_of_headers == 0) return -1; - else ptr += 4; - - if( te == none) { - - if(content_length > 0) return ptr-streamptr + content_length; - else if( reqresp == request ) return ptr-streamptr; - else if( reqresp == response ) return -1; - - } else if(te == notchunked) { + // skip the empty line + stream+=line_length; + stream_length-=line_length; - if( reqresp == request ) return ptr-streamptr; - else return -1; - - } else if(te == chunked) { - - const unsigned char* chunksize_ptr = ptr; - while(ptr-streamptr + 2 <= stream_length && end_of_chunklngth == 0) - { - if(memcmp(ptr, (const char*)crlf, 2) == 0) end_of_chunklngth = 1; - else ptr++; + // See RFC7230 3.3.3 + if( !is_request && ( head_req || (resp_code==204) || (resp_code==304) || (resp_code>=100 && resp_code<=199))){ // See RFC7230 3.3.3 1. + // no body + const char *stream_begin=(const char *)(const unsigned char *)pl__stream; + return stream-stream_begin; + } else if(!is_request && connect_req && (resp_code>=200 && resp_code<=299)){ // See RFC7230 3.3.3 2. + // no body + const char *stream_begin=(const char *)(const unsigned char *)pl__stream; + return stream-stream_begin; + } else if(is_chunked){ // See RFC7230 3.3.3 3. + int chunk_length=-1; + if((line_length=get_http_line(stream,stream_length))==-1){ + return -1; } - if(end_of_chunklngth == 0) return 0; - - int chunk_length = (int)strtol((const char*)chunksize_ptr, NULL, 16); - - while(chunk_length != 0 && ptr-streamptr <= stream_length) - { - end_of_chunklngth = 0; - - // chunksize + \r\n + next char - ptr += chunk_length + 2 + 1; - - chunksize_ptr = ptr; - while(ptr-streamptr + 2 <= stream_length && end_of_chunklngth == 0) - { - if(memcmp(ptr, (const char*)crlf, 2) == 0) end_of_chunklngth = 1; - else ptr++; + chunk_length=(int)strtol(stream, NULL, 16); + stream+=line_length; + stream_length-=line_length; + while(chunk_length>0){ + if(chunk_length<=stream_length){ // skip the chunk data + stream+=chunk_length; + stream_length-=chunk_length; + } + // read the CRLF + if((line_length=get_http_line(stream,stream_length))!=2){ + return -1; + } + stream+=line_length; + stream_length-=line_length; + // read the next chunk size + if((line_length=get_http_line(stream,stream_length))==-1){ + return -1; } - if(end_of_chunklngth == 0) return -1; - else chunk_length = (int)strtol((const char*)chunksize_ptr, NULL, 16); + chunk_length=(int)strtol(stream, NULL, 16); + stream+=line_length; + stream_length-=line_length; } - if(chunk_length > 0) return -1; - - //find \r\n\r\n - while(ptr-streamptr + 4 <= stream_length && end_of_msg == 0) - { - if( memcmp(ptr, (const char*)crlfcrlf, 4) == 0) end_of_msg = 1; - else ptr++; + // skip trailers + while((line_length=get_http_line(stream,stream_length))!=2){ + if(line_length==-1){ // there is no whole line in the buffer + return -1; + } + stream+=line_length; + stream_length-=line_length; } - if(end_of_msg == 0) return -1; - - return ptr+4-streamptr; + // skip the final CRLF + stream+=line_length; + stream_length-=line_length; + const char *stream_begin=(const char *)(const unsigned char *)pl__stream; + return stream-stream_begin; + } else if(content_length>=0){ // See RFC7230 3.3.3 5. + const char *stream_begin=(const char *)(const unsigned char *)pl__stream; + return stream-stream_begin+content_length; + } else if(is_request){ // See RFC7230 3.3.3 6. + const char *stream_begin=(const char *)(const unsigned char *)pl__stream; + return stream-stream_begin; + } else if(connClosed){ // See RFC7230 3.3.3 7. + return pl__stream.lengthof(); } return -1; + + } + + INTEGER ef__HTTPMessage__len(const OCTETSTRING& pl__stream) + { + return(f_HTTPMessage_len_common(pl__stream, false,false,false)); + } + + INTEGER ef__HTTPMessage__len__forConnectResp(const OCTETSTRING& pl__stream) + { + return(f_HTTPMessage_len_common(pl__stream, false,false,true)); } + + INTEGER ef__HTTPMessage__len__forHeadResp(const OCTETSTRING& pl__stream) + { + return(f_HTTPMessage_len_common(pl__stream, false,true,false)); + } + + INTEGER ef__HTTPMessage__len__forConnClosed(const OCTETSTRING& pl__stream) + { + return(f_HTTPMessage_len_common(pl__stream, true,false,false)); + } + } diff --git a/src/HTTP_Types.ttcn b/src/HTTP_Types.ttcn index 793f5f31aa3cc74a39ba0700e25109f84b0916cd..803999a9c47811608133a109db763858c4aba985 100644 --- a/src/HTTP_Types.ttcn +++ b/src/HTTP_Types.ttcn @@ -9,7 +9,7 @@ ******************************************************************************/ // // File: HTTP_Types.ttcn -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se // Reference: RFC7230 - RFC7235 @@ -165,4 +165,4 @@ module HTTP_Types charstring raw_message } -}with {extension "version R1C"} +}with {extension "version R1D"} diff --git a/src/HTTP_parse.h b/src/HTTP_parse.h index 8ecc1ac784138b48ae99fdefff88ffa7b572ce73..913e4b8325c91ace1eef6b5ff65d816c03cc53b0 100644 --- a/src/HTTP_parse.h +++ b/src/HTTP_parse.h @@ -9,7 +9,7 @@ ******************************************************************************/ // // File: HTTP.y -// Rev: R1C +// Rev: R1D // Prodnr: CNL113 // Updated: 2014-10-10 // Contact: http://ttcn.ericsson.se diff --git a/src/HTTP_parse.l b/src/HTTP_parse.l index a025018ad648bcae3a47514f4e00e6f0e981ac32..dbf76a58d3e343d7aed0da3047a3ca05b18b299f 100644 --- a/src/HTTP_parse.l +++ b/src/HTTP_parse.l @@ -12,7 +12,7 @@ ******************************************************************************/ // // File: HTTP.l -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se // Reference: RFC7230 - RFC7235 diff --git a/src/HTTP_parse.y b/src/HTTP_parse.y index f2b8982775699fed3222665fc6cf3e57ac6addd5..02603bcf2326fe7c8cf653031e317aaf680c0e7b 100644 --- a/src/HTTP_parse.y +++ b/src/HTTP_parse.y @@ -11,7 +11,7 @@ ******************************************************************************/ // // File: HTTP_parse.y -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se // Reference: RFC7230 - RFC7235 diff --git a/src/HTTP_parse_.tab.c b/src/HTTP_parse_.tab.c index ad48af81eb1064cc97ce80580f29dc043dfd770a..859eacc0f47472ce2456a634804a3085a811d90f 100644 --- a/src/HTTP_parse_.tab.c +++ b/src/HTTP_parse_.tab.c @@ -88,7 +88,7 @@ ******************************************************************************/ // // File: HTTP_parse.y -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se // Reference: RFC7230 - RFC7235 diff --git a/src/lex.HTTP_parse_.c b/src/lex.HTTP_parse_.c index 4766465bd82db0cdd18836e8a746294210e93db5..74cbd06219843ff530b2b38b1e3a52cb2b007c8b 100644 --- a/src/lex.HTTP_parse_.c +++ b/src/lex.HTTP_parse_.c @@ -2984,7 +2984,7 @@ char *HTTP_parse_text; ******************************************************************************/ // // File: HTTP.l -// Rev: R1C +// Rev: R1D // Prodnr: CNL113796 // Contact: http://ttcn.ericsson.se // Reference: RFC7230 - RFC7235