dav_ssize_t find_next_part(HttpRequest& req, const std::string & boundary, dav_ssize_t current_offset, const dav_ssize_t request_size, dav_size_t* part_size, dav_off_t* part_offset, DavixError** err){ dav_ssize_t tmp_read_size =0; int n_try =0; char buffer[DAVIX_READ_BLOCK_SIZE+1]; buffer[DAVIX_READ_BLOCK_SIZE]= '\0'; // read first line, check and try to find boundary pattern, ignore some empty line if present while(n_try++ < 10 && tmp_read_size ==0){ if( (tmp_read_size = req.readLine(buffer, DAVIX_READ_BLOCK_SIZE, err)) <0 ) return -1; } if(n_try >= 10){ HttpIoVecSetupErrorMultiPart(err); return -1; } current_offset +=tmp_read_size; if(tmp_read_size == DAVIX_READ_BLOCK_SIZE || current_offset >= request_size){ HttpIoVecSetupErrorMultiPart(err); return -1; } if( is_a_start_boundary_part(buffer, tmp_read_size, boundary, err) == false) return -1; return find_and_analyze_multi_part_headers(req, boundary, current_offset, request_size, part_size, part_offset, err); }
dav_ssize_t find_and_analyze_multi_part_headers(HttpRequest& req, const std::string & boundary, dav_ssize_t current_offset, const dav_ssize_t request_size, dav_size_t* part_size, dav_off_t* part_offset, DavixError** err){ dav_ssize_t tmp_read_size =0; char buffer[DAVIX_READ_BLOCK_SIZE+1]; buffer[DAVIX_READ_BLOCK_SIZE]= '\0'; while((tmp_read_size = req.readLine(buffer, DAVIX_READ_BLOCK_SIZE, err)) > 0 && (current_offset += tmp_read_size) < request_size){ int res = find_header_params(buffer, part_size,part_offset); switch(res){ case 0: break; case 1: return find_end_header_multi_part(req, boundary, current_offset, request_size, err); break; default: HttpIoVecSetupErrorMultiPart (err); return -1; } } HttpIoVecSetupErrorMultiPart(err); return -1; }
inline char* header_delimiter(char* buffer, DavixError** err){ char* p; if( (p =strchr(buffer, ':')) == NULL){ HttpIoVecSetupErrorMultiPart(err); } return p; }
int check_multi_part_content_type(const HttpRequest& req, std::string & boundary, DavixError** err){ std::string buffer; if( req.getAnswerHeader(ans_header_content_type, buffer) == true // has content type && http_extract_boundary_from_content_type(buffer, boundary, err) == 0){ return 0; } HttpIoVecSetupErrorMultiPart(err); return -1; }
static bool find_corresponding_part(std::deque<PartPtr> & parts, dav_size_t part_size, dav_off_t part_off_set, std::deque<PartPtr>::iterator & res, DavixError** err){ for(std::deque<PartPtr>::iterator it = parts.begin(); it != parts.end();it++){ if( (*it).first->diov_offset == part_off_set && (*it).first->diov_size == part_size){ res= it; DAVIX_TRACE(" Match a vec io chunk offset: %ld size: %ld", part_off_set, part_size); return true; } } HttpIoVecSetupErrorMultiPart(err); return false; }
bool is_a_start_boundary_part(char* buffer, size_t s_buff, const std::string & boundary, DavixError** err){ if(s_buff > 3){ char * p = buffer; if( *p == '-' && *(p+1)== '-'){ if( strcmp(buffer+2, boundary.c_str()) ==0){ return true; } } } DAVIX_TRACE("Invalid boundary delimitation"); HttpIoVecSetupErrorMultiPart(err); return false; }
int http_extract_boundary_from_content_type(const std::string & buffer, std::string & boundary, DavixError** err){ size_t pos_bound; static const std::string delimiter = "\";"; if( (pos_bound= buffer.find(ans_header_boundary_field)) != std::string::npos){ std::vector<std::string> tokens = stringTokSplit(buffer.substr(pos_bound + ans_header_boundary_field.size()), delimiter); if( tokens.size() >= 1 && tokens[0].size() > 0 && tokens[0].size() <= 70){ DAVIX_TRACE("Multi part content type : %s", boundary.c_str()); std::swap(boundary,tokens[0]); return 0; } } HttpIoVecSetupErrorMultiPart(err); return -1; }
ssize_t HttpVecOps::parseMultipartRequest(const DavIOVecInput *input_vec, DavIOVecOuput * output_vec, const dav_size_t count_vec, DavixError** err){ std::string boundary; dav_ssize_t file_size; dav_ssize_t current_offset=0; ssize_t ret = 0; DAVIX_TRACE(" -> Davix multi part parsing"); if(( file_size = _req.getAnswerSize() )== -1 || check_multi_part_content_type(_req, boundary, err) != 0 ){ DAVIX_TRACE("Invalid Header Content info for multi part request"); HttpIoVecSetupErrorMultiPart(err); return -1; } std::deque<PartPtr> parts; for(dav_size_t i =0; i < count_vec; ++i) parts.push_back(PartPtr(input_vec+i, output_vec+i)); while(ret >= 0 && parts.size() > 0){ dav_size_t part_size; dav_off_t part_off_set; ssize_t tmp_ret; if( ( current_offset = find_next_part(_req, boundary, current_offset, file_size, &part_size, &part_off_set, err)) < 0){ return -1; } std::deque<PartPtr>::iterator part; if( find_corresponding_part(parts, part_size, part_off_set, part, err) == false){ return -1; } if( (tmp_ret = copy_and_configure(_req, part, err)) < 0) return -1; ret += tmp_ret; parts.erase(part); } DAVIX_TRACE(" <- Davix multi part parsing"); return ret; }
int parse_multi_part_header(HttpRequest& req, const std::string & boundary, ChunkInfo & info, int & n_try, DavixError** err){ dav_ssize_t ret =0; char buffer[DAVIX_READ_BLOCK_SIZE+1] = {0}; if(n_try > 100){ HttpIoVecSetupErrorMultiPartTooLong(err); return -1; } if( (ret = parse_multi_part_header_line(req, buffer, err)) <0 ){ return -1; } if(!info.bounded){ if(ret == 0) // start with crlf return parse_multi_part_header(req, boundary, info, ++n_try, err); BoundaryType type = parseBoundary(buffer, boundary); if(type == NOT_A_BOUNDARY) return -1; if(type == TERMINATING_BOUNDARY) return -2; info.bounded = true; return parse_multi_part_header(req, boundary, info, ++n_try, err); } if( info.offset == 0 && info.size == 0){ if( find_header_params(buffer, ret, &(info.size), &(info.offset)) < 0) return -1; return parse_multi_part_header(req, boundary, info, ++n_try, err); } if(ret == 0) // end crlf return 0; HttpIoVecSetupErrorMultiPart(err); return -1; }