commit 9af6d960a4cc47d4cbbecd2df71214685beff767 parent 09e32aed93fea2c51eb72d0858e599508663c181 Author: Michael Savage <mikejsavage@gmail.com> Date: Fri Nov 18 21:00:00 +0200 Add HTTP module Diffstat:
http.cc | | | 93 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
http.h | | | 26 | ++++++++++++++++++++++++++ |
diff --git a/http.cc b/http.cc @@ -0,0 +1,93 @@ +#include <sys/types.h> +#include <sys/socket.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <unistd.h> + +#include <string> + +#include "../intrinsics.h" +#include "http.h" + +bool dns_first( const char * host, struct sockaddr_storage * address ) { + struct addrinfo hints; + memset( &hints, 0, sizeof( struct addrinfo ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + struct addrinfo * addresses; + int ok = getaddrinfo( "mikejsavage.co.uk", "http", &hints, &addresses ); + if( ok != 0 ) { + return false; + } + + memmove( address, addresses->ai_addr, addresses->ai_addrlen ); + freeaddrinfo( addresses ); + + return true; +} + +GetResult http_get( const struct sockaddr_storage & address, const char * host, const char * path, std::string * body ) { + int sock = socket( address.ss_family, SOCK_STREAM, 0 ); + if( sock == -1 ) { + return GET_ERROR_SOCKET; + } + SCOPE_EXIT( close( sock ) ); + + if( connect( sock, ( const sockaddr * ) &address, sizeof( address ) ) == -1 ) { + return GET_ERROR_CONNECT; + } + + char request[ 2048 ]; + int request_len = snprintf( request, sizeof( request ), + "GET %s HTTP/1.1\r\n" + "Host: %s\r\n" + "Connection: close\r\n" + "User-Agent: medfall\r\n" + // "Range: bytes=%llu-\r\n" + "\r\n\r\n", path, host ); + + if( request_len < 0 || checked_cast< size_t >( request_len ) >= sizeof( request ) ) { + return GET_ERROR_IO; + } + + ssize_t bytes_written = send( sock, request, request_len, 0 ); + if( bytes_written == -1 ) { + return GET_ERROR_IO; + } + + std::string response; + char buf[ BUFSIZ ]; + while( true ) { + ssize_t bytes_read = recv( sock, buf, sizeof( buf ), 0 ); + if( bytes_read == -1 ) { + return GET_ERROR_IO; + } + + if( bytes_read == 0 ) { + break; + } + + response.append( buf, checked_cast< size_t >( bytes_read ) ); + } + + // HTTP/1.1 200 OK + // 0123456789 + std::string response_code = response.substr( 9, 3 ); + if( response_code == "400" ) return GET_ERROR_HTTP_BAD_REQUEST; + if( response_code == "404" ) return GET_ERROR_HTTP_NOT_FOUND; + if( response_code == "500" ) return GET_ERROR_HTTP_INTERNAL_SERVER_ERROR; + if( response_code != "200" ) return GET_ERROR_HTTP_OTHER; + + size_t body_start = response.find( "\r\n\r\n" ); + if( body_start == std::string::npos ) { + return GET_ERROR_HTTP_OTHER; + } + + body->append( response, body_start + strlen( "\r\n\r\n" ), std::string::npos ); + + return GET_OK; +} diff --git a/http.h b/http.h @@ -0,0 +1,26 @@ +#ifndef _HTTP_H_ +#define _HTTP_H_ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <string> + +#include "intrinsics.h" + +enum GetResult { + GET_OK, + GET_ERROR_DNS, + GET_ERROR_SOCKET, + GET_ERROR_CONNECT, + GET_ERROR_IO, + GET_ERROR_HTTP_BAD_REQUEST, + GET_ERROR_HTTP_NOT_FOUND, + GET_ERROR_HTTP_INTERNAL_SERVER_ERROR, + GET_ERROR_HTTP_OTHER, +}; + +bool dns_first( const char * host, struct sockaddr_storage * address ); +GetResult http_get( const struct sockaddr_storage & address, const char * host, const char * path, std::string * body ); + +#endif // _HTTP_H_