Hola acabo de hacer una clase para organizar mas o menos el header de una peticion HTTP. Como esto:
HTTP/1.1 200 OK\r\n
Date: Mon, 23 May 2005 22:38:34 GMT\r\n
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)\r\n
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT\r\n
ETag: "3f80f-1b6-3e1cb03b"\r\n
Content-Type: text/html; charset=UTF-8\r\n
Content-Length: 131\r\n
Connection: close\r\n
\r\n
HTTP_class.hpp
#ifndef HTTP_CLASS_HPP
#define HTTP_CLASS_HPP
#include <string>
#include <ctime>
#include <vector>
using namespace std;
//CLASS STATE
#define SETUP_OK 1
#define SETUP_NEED 2
#define INVALID_HEADER 3
//HTTP CODES
//Informational
#define H_Continue 100
#define H_Switching_Protocols 101
#define H_Processing 102
//Success
#define H_OK 200
#define H_Created 201
#define H_Accepted 202
#define H_Non_Authoritative_Information 203
#define H_No_Content 204
#define H_Reset_Content 205
#define H_Partial_Content 206
#define H_Multi_Status 207
#define H_Already_Reported 208
#define H_IM_Used 226
//Redirection
#define H_Multiple_Choices 300
#define H_Moved_Permanently 301
#define H_Found 302
#define H_See_Other 303
#define H_Not_Modified 304
#define H_Use_Proxy 305
#define H_Switch_Proxy 306
#define H_Temporary_Redirect 307
#define H_Permanent_Redirect 308
//Client Error
#define H_Bad_Request 400
#define H_Unauthorized 401
#define H_Payment_Required 402
#define H_Forbidden 403
#define H_Not_Found 404
#define H_Method_Not_Allowed 405
#define H_Not_Acceptable 406
#define H_Proxy_Authentication_Required 407
#define H_Request_Timeout 408
#define H_Conflict 409
#define H_Gone 410
#define H_Length_Required 411
#define H_Precondition_Failed 412
#define H_Request_Entity_Too_Large 413
#define H_Request_URI_Too_Long 414
#define H_Unsupported_Media_Type 415
#define H_Requested_Range_Not_Satisfiable 416
#define H_Expectation_Failed 417
#define H_Im_a_teapot 418
#define H_Authentication_Timeout 419
#define H_Method_Failure 420
#define Enhance_Your_Calm 420
#define H_UnprocessableEntity 422
#define H_Locked 423
#define H_Failed_Dependency 424
#define H_Upgrade_Required 426
#define H_Precondition_Required 428
#define H_Too_Many_Requests 429
#define H_Request_Header_Fields_Too_Large 431
#define H_Login_Timeout 440
#define H_No_Response 444
#define H_Retry_With 449
#define H_Blocked_by_Windows_Parental_Controls 450
#define H_Unavailable_For_Legal_Reasons 451
#define H_Redirect 494
#define H_Request_Header_Too_Large 495
#define H_Cert_Error 496
#define H_No_Cert 497
#define H_HTTP_to_HTTPS 498
#define H_Token_expired_invalid 499
#define H_Client_Closed_Request 499
#define H_Token_required 499
//class ContentType{
//public:
// string type;
// string charset;
//};
class HTTP{
public:
HTTP();
HTTP(string header);
bool setup(string header);
int Code();//HTTP status
const int State();//class status
tm Date();
string Server();
tm Last_Modified();
string ETag();
string Content_Type();
int Content_Lenght();
string Connection();
string Other(string name);
vector<string> Other(int i);
//helpful functions
double HTTPVersion();
int Size();//Size of fields
private:
int state;//Already setup?
int code;
tm date;
string server;
tm last_modified;
string etag;
string content_type;
int content_length;
string header;
string connection;
vector < vector<string> > all; //all fields
//helpful data
double version;
//Config functions
tm getDate(string date);
void defaultConfig();
};
vector<string> split(string full, string part); //helpful function
#endif
HTTP_class.cpp
#include "http_class.hpp"
#include <regex>
HTTP::HTTP(){
defaultConfig();
}
HTTP::HTTP(string header){
defaultConfig();
setup(header);
}
string HTTP::Other(string name){
for (int i = 0; i < all.size(); i++){
if (all[i][0] == name){
return all[i][1];
}
}
return "";
}
vector<string> HTTP::Other(int i){
if (i < all.size())
return all[i];
else
return vector<string>();
}
bool HTTP::setup(string header){
vector<string> parts = split(header, "\r\n");
//all setup
for (int i = 1; i < parts.size(); i++){
all.push_back(split(parts[i],": " ));
}
all.pop_back(); // remove last 2 \r\n of the end of http protocol
all.pop_back(); //
//end
if (all.size() < 1){ //Nothing founded
state = INVALID_HEADER;
return false;
}
//http setup
string v = parts[0].substr(5, 3);
version = atof(v.c_str());
code = atoi(parts[0].substr(8, 4).c_str());
//end
date = getDate(Other("Date"));
server = Other("Server");
last_modified = getDate(Other("Last-Modified"));
etag = Other("ETag");
content_type = Other("Content-Type");//Mejores en 2.0
content_length = atoi(Other("Content-Length").c_str());
connection = Other("Connection");
state = SETUP_OK;
return true;
}
int HTTP::Code(){
return code;
}
const int HTTP::State(){
return state;
}
tm HTTP::Date(){
//Example of check
if (date.tm_year != 0 && state == SETUP_OK){ // if == 0 no date in header
return date;
}
}
string HTTP::Server(){
return server;
}
tm HTTP::Last_Modified(){
return last_modified;
}
string HTTP::ETag(){
return etag;
}
string HTTP::Content_Type(){
return content_type;
}
int HTTP::Content_Lenght(){
return content_length;
}
string HTTP::Connection(){
return connection;
}
//Helpful functions
double HTTP::HTTPVersion(){
return version;
}
int HTTP::Size(){
return all.size();
}
tm HTTP::getDate(string _date){ //Get date in tm format for example in Date or Last-Modified
tm date = tm();
if (_date.size() > 0){
const static string months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
smatch match;
if (_date.find("GMT") != -1){ // New format
if (regex_search(_date, match, regex("^\\w{3,9},\\s(\\d{2})[\\s\\-](\\w{3})[\\s\\-](\\d{2,4})\\s(\\d{2}):(\\d{2}):(\\d{2}) GMT$"))){
date.tm_mday = atoi(match[1].str().c_str());
int month;
for (int i = 0; i < sizeof(months); i++){
if (months[i] == match[2].str()){
month = i;
break;
}
}
date.tm_mon = month;
int year = atoi(match[3].str().c_str());
if (year > 1900)
year -= 1900;
date.tm_year = year;
date.tm_hour = atoi(match[4].str().c_str());
date.tm_min = atoi(match[5].str().c_str());
date.tm_sec = atoi(match[6].str().c_str());
}
}
else{ //Old ANSI format
if (regex_search(_date, match, regex("^\\w{3} (\\w{3}) (\\d{1,2}) (\\d{2}):(\\d{2}):(\\d{2}) (\\d{4})$"))){
int month;
for (int i = 0; i < sizeof(months); i++){
if (months[i] == match[1].str()){
month = i;
break;
}
}
date.tm_mday = atoi(match[2].str().c_str());
date.tm_hour = atoi(match[3].str().c_str());
date.tm_min = atoi(match[4].str().c_str());
date.tm_sec = atoi(match[5].str().c_str());
date.tm_year = atoi(match[6].str().c_str());
}
}
}
return date;
}
void HTTP::defaultConfig(){ //Set some values help to don't check state in every function
state = SETUP_NEED;
code = 0;
version = 0;
content_length = 0;
}
//split string in vector
vector<string> split(string full, string part){
vector<string> parts;
int last = 0;
int p;
while ((p = full.find(part, last)) != -1){
parts.push_back(full.substr(last, p - last));
last = p + part.size();
}
parts.push_back(full.substr(last, full.size()));
return parts;
}
Ejemplo conexión http con win sockets
#include <iostream>
#include <string>
#include <vector>
#include <WinSock2.h>
#include "http_class.hpp"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
#define SIZE 1024
int main(){
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
char buffer[SIZE];
vector<vector<string>>links = { //Random urls
{ "foro.elhacker.net", "/throw 403 error" },
{ "foro.elhacker.net", "/throw_302_error" },
{ "www.google.es", "/" },
{ "foro.elhacker.net", "/ingenieria_inversa-b26.0/" }
};
hostent * host;
in_addr ip;
sockaddr_in data;
string request;
for (int i = 0; i < links.size(); i++){
host = gethostbyname(links[i][0].c_str());
ip.s_addr = *(long * )host->h_addr_list[0];
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET){
cout << "Invalid socket";
return 1;
}
memset(&data, 0, sizeof(sockaddr_in));
data.sin_addr = ip;
data.sin_family = AF_INET;
data.sin_port = htons(80);
if(connect(sock, (sockaddr*)&data, sizeof(sockaddr_in))){
cout << "Connection with " << inet_ntoa(ip) << " failed.";
return 1;
}
request = "GET " + links[i][1] + " HTTP/1.0\r\n";
request += "Host: " + links[i][0] + "\r\n";
request += "\r\n";
if (send(sock, request.c_str(), request.size(), 0) != request.size()){
cout << "Send error";
return 1;
}
//Accept
char buffer[SIZE];
int lastBytes = SIZE - 1;//bytes recerved
string response;
while (lastBytes > 0){
lastBytes = recv(sock, buffer, sizeof(buffer), 0);
if (lastBytes > 0)
response += string(buffer).substr(0, lastBytes);
}
string header = response.substr(0, response.find("\r\n\r\n") + 4);
HTTP http(header);
// or
//http.setup(header);
cout << "Host: " << links[i][0] << endl;
cout << "HTTP version: " << http.HTTPVersion() << endl;
if (http.Code() == H_Not_Found){
cout << "Path: " << links[i][1] << " wasn't founded";
}
else if (http.Code() == H_Forbidden){
cout << "Server Forbidden message";
if (http.Other("Location").size() > 0){//Location field
cout << " to " << http.Other("Location");
}
}
else{
cout << "Status code: " << http.Code();
}
cout << "\n\nAll fields: \n";
for (int i = 0; i < http.Size(); i++){
cout << http.Other(i)[0] << ": " << http.Other(i)[1] << endl;
}
cout << endl << endl;
}
fflush(stdin);
getchar();
return 0;
}
Descargar ejemplo:
http://pruebasdephp.hol.es/things/HTTP_class.rarProbado en visual studio 2013
Si me pueden dar ideas de que puedo mejorar o si tienen alguna duda
Saludos