void Global_Config::load(int argc,char *argv[],char const *def) { if(loaded) { return; } char const *def_file=def; int i; for(i=1; i<argc; i++) { if(strncmp(argv[i],"--config=",9)==0) { def_file=argv[i]+9; break; } else if(strcmp(argv[i],"-c")==0 && i+1<argc) { def_file=argv[i+1]; break; } } if(def_file==NULL) { throw HTTP_Error("Configuration file not defined"); } load(def_file); }
bool Global_Config::get_tocken(FILE *f,tocken_t &T) { int c; while((c=fgetc(f))!=EOF) { if(c=='.') { T.first='.'; return true; } else if(c=='=') { T.first='='; return true; } else if(c=='\n') { line_counter++; continue; } else if(c==' ' || c=='\r' || c=='\t') { continue; } else if(isalpha(c)) { T.second=""; T.second.reserve(32); T.second+=(char)c; while((c=fgetc(f))!=EOF && (isalnum(c) || c=='_')) { T.second+=(char)c; } if(c!=EOF) { ungetc(c,f); } T.first=WORD; return true; } else if(isdigit(c) || c=='-') { T.second=""; T.second.reserve(32); T.second+=(char)c; T.first=INT; while((c=fgetc(f))!=EOF && isdigit(c)) { T.second+=(char)c; } if(c=='.') { T.second+='.'; T.first=DOUBLE; while((c=fgetc(f))!=EOF && isdigit(c)) { T.second+=(char)c; } } if(T.second=="-" || T.second=="." || T.second=="-.") { throw HTTP_Error("Illegal charrecters"); } if(c!=EOF) { ungetc(c,f); } return true; } else if(c=='\"') { T.first=STR; T.second=""; T.second.reserve(128); for(;;) { c=fgetc(f); if(c=='\\') { if((c=fgetc(f))=='\"' ) { T.second+='"'; continue; } else { T.second+='\\'; } } if(c==EOF) { throw HTTP_Error("Unexpected EOF "); } if(c=='\n') line_counter++; if(c=='\"') { return true; } T.second+=(char)c; } } else if(c=='#' || c==';') { while((c=fgetc(f))!=EOF) { if(c=='\n') { line_counter++; break; } } if(c==EOF) { return false; } } else { throw HTTP_Error(string("Unexpected charrecter")+(char)c); } } return false; }
void Global_Config::load(char const *fname) { if(loaded) { return; } FILE *f=fopen(fname,"r"); line_counter=1; if(!f) { throw HTTP_Error(string("Failed to open file:")+fname); } tocken_t T; string key; int state=0; try { while(get_tocken(f,T) && state != 5) { switch(state) { case 0: if(T.first != WORD) { state=5; } else { key=T.second; state=1; } break; case 1: if(T.first != '.') state=5; else state=2; break; case 2: if(T.first!=WORD) { state=5; } else { state=3; key+='.'; key+=T.second; } break; case 3: if(T.first!= '=') state=5; else state=4; break; case 4: if(T.first==INT) { long val=atol(T.second.c_str()); long_map.insert(pair<string,long>(key,val)); } else if(T.first==DOUBLE) { double val=atof(T.second.c_str()); double_map.insert(pair<string,double>(key,val)); } else if(T.first==STR) { string_map.insert(pair<string,string>(key,T.second)); } else { state=5; break; } state=0; break; } } if(state!=0) { throw HTTP_Error("Parsing error"); } } catch (HTTP_Error &err) { fclose(f); char stmp[32]; snprintf(stmp,32," at line %d",line_counter); throw HTTP_Error(string(err.get())+stmp); } fclose(f); loaded=true; }
Response http_sync(http_exch_fn http_transact, const std::string& verb, const std::string& url, const std::string& content_type, const std::vector<byte>& body, size_t allowable_redirects) { if(url.empty()) throw HTTP_Error("URL empty"); const auto protocol_host_sep = url.find("://"); if(protocol_host_sep == std::string::npos) throw HTTP_Error("Invalid URL '" + url + "'"); const auto host_loc_sep = url.find('/', protocol_host_sep + 3); std::string hostname, loc; if(host_loc_sep == std::string::npos) { hostname = url.substr(protocol_host_sep + 3, std::string::npos); loc = "/"; } else { hostname = url.substr(protocol_host_sep + 3, host_loc_sep-protocol_host_sep-3); loc = url.substr(host_loc_sep, std::string::npos); } std::ostringstream outbuf; outbuf << verb << " " << loc << " HTTP/1.0\r\n"; outbuf << "Host: " << hostname << "\r\n"; if(verb == "GET") { outbuf << "Accept: */*\r\n"; outbuf << "Cache-Control: no-cache\r\n"; } else if(verb == "POST") outbuf << "Content-Length: " << body.size() << "\r\n"; if(!content_type.empty()) outbuf << "Content-Type: " << content_type << "\r\n"; outbuf << "Connection: close\r\n\r\n"; outbuf.write(reinterpret_cast<const char*>(body.data()), body.size()); std::istringstream io(http_transact(hostname, outbuf.str())); std::string line1; std::getline(io, line1); if(!io || line1.empty()) throw HTTP_Error("No response"); std::stringstream response_stream(line1); std::string http_version; unsigned int status_code; std::string status_message; response_stream >> http_version >> status_code; std::getline(response_stream, status_message); if(!response_stream || http_version.substr(0,5) != "HTTP/") throw HTTP_Error("Not an HTTP response"); std::map<std::string, std::string> headers; std::string header_line; while (std::getline(io, header_line) && header_line != "\r") { auto sep = header_line.find(": "); if(sep == std::string::npos || sep > header_line.size() - 2) throw HTTP_Error("Invalid HTTP header " + header_line); const std::string key = header_line.substr(0, sep); if(sep + 2 < header_line.size() - 1) { const std::string val = header_line.substr(sep + 2, (header_line.size() - 1) - (sep + 2)); headers[key] = val; } } if(status_code == 301 && headers.count("Location")) { if(allowable_redirects == 0) throw HTTP_Error("HTTP redirection count exceeded"); return GET_sync(headers["Location"], allowable_redirects - 1); } std::vector<byte> resp_body; std::vector<byte> buf(4096); while(io.good()) { io.read(reinterpret_cast<char*>(buf.data()), buf.size()); resp_body.insert(resp_body.end(), buf.data(), &buf[io.gcount()]); } const std::string header_size = search_map(headers, std::string("Content-Length")); if(!header_size.empty()) { if(resp_body.size() != to_u32bit(header_size)) throw HTTP_Error("Content-Length disagreement, header says " + header_size + " got " + std::to_string(resp_body.size())); } return Response(status_code, status_message, resp_body, headers); }