Skip to content

Instantly share code, notes, and snippets.

@opsJson
Last active January 7, 2022 03:49
Show Gist options
  • Save opsJson/de111a99e11b279fecf9ad1cb4a0a1fe to your computer and use it in GitHub Desktop.
Save opsJson/de111a99e11b279fecf9ad1cb4a0a1fe to your computer and use it in GitHub Desktop.
Easily make HTTP requests over internet, on Windows.
#include <winsock2.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
/*///////////////////////////////////
easy-strings
///////////////////////////////////*/
int indexOf(char* source, char* key, int pos) {
int i, j, dest;
assert(pos > -1);
for (i=0, j=0, dest=0; i<strlen(source); i++) {
(source[i] == key[j]) ? (j++) : (j=0);
if (j == strlen(key)) {
j = 0;
dest = i;
if (pos == 0) return dest - strlen(key) +1;
pos--;
}
}
return -1;
}
char* substring(char* source, int start, int end) {
int i;
char *dest, *back;
assert(start > -1);
assert(end > -1);
assert(start <= end);
dest = malloc(sizeof(char) * strlen(source) +1);
assert(dest != NULL);
strcpy(dest, source);
back = dest;
dest = dest + start;
*(dest + end - start + 1) = 0;
strcpy(back, dest);
return back;
}
/*///////////////////////////////////
implementation
///////////////////////////////////*/
typedef struct routes {
char *version;
char *statusline;
char *headers;
char *body;
} *Response;
Response go(char* url, char* data, char* custom_headers, char* force_method, char* alternative_port, ...) {}
#define go(...) _go(__VA_ARGS__, "", "", "", "")
Response _go(char* url, char* data, char* custom_headers, char* force_method, char* alternative_port, ...) {
//variables
WSADATA wsa;
SOCKET s;
struct routes *r;
struct sockaddr_in serverToConnect;
struct hostent* he;
struct in_addr **addr_list;
char *domain, *resource, *msg, method[20], *response;
int size, port, content_length;
//init
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
fprintf(stderr, "Couldn't start winsock with error %i\n", WSAGetLastError());
return 0;
}
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
fprintf(stderr, "Couldn't create a socket with error %i\n", WSAGetLastError());
return 0;
}
//setting domain
if (indexOf(url, "//", 0) != -1) {
if (indexOf(url, "/", 2) != -1)
domain = substring(url, indexOf(url, "//", 0)+2, indexOf(url, "/", 2)-1);
else
domain = substring(url, indexOf(url, "//", 0)+2, strlen(url));
}
else {
if (indexOf(url, "/", 0) != -1)
domain = substring(url, 0, indexOf(url, "/", 0)-1);
else
domain = substring(url, 0, strlen(url));
}
if ((he = gethostbyname(domain)) == NULL) {
fprintf(stderr, "Couldn't get information from host with error %i\n", WSAGetLastError());
return 0;
}
//setting connection
addr_list = (struct in_addr **) he->h_addr_list;
if (atoi(alternative_port) == 0) port = 80;
else port = atoi(alternative_port);
serverToConnect.sin_addr.s_addr = inet_addr(inet_ntoa(*addr_list[0]));
serverToConnect.sin_port = htons(port);
serverToConnect.sin_family = AF_INET;
//setting resource
if (indexOf(url, "//", 0) != -1) {
if (indexOf(url, "/", 2) != -1)
resource = substring(url, indexOf(url, "/", 2), strlen(url));
else
resource = "/";
}
else {
if (indexOf(url, "/", 0) != -1)
resource = substring(url, indexOf(url, "/", 0), strlen(url));
else
resource = "/";
}
//setting method
if (strlen(force_method) == 0) {
if (strlen(data) == 0) strcpy(method, "GET");
else strcpy(method, "POST");
} else {
strcpy(method, force_method);
}
//setting content-length
if (strlen(data) > 0) content_length = strlen(data)+3;
else content_length = 0;
//preparing request
msg = (char*)malloc( (sizeof(char) * strlen(method))
+ (sizeof(char) * strlen(resource))
+ (sizeof(char) * strlen(domain))
+ (sizeof(int)) //content_length
+ (sizeof(char) * strlen(custom_headers))
+ (sizeof(char) * strlen(data))
+ 50);
sprintf(msg, "%s %s HTTP/1.1\n"
"Host: %s\n"
"Content-Length: %lu\n"
"%s"
"\n\n"
"%s", method, resource, domain, content_length, custom_headers, data);
//connecting
if (connect(s, (struct sockaddr*)&serverToConnect, sizeof(serverToConnect)) == SOCKET_ERROR) {
fprintf(stderr, "Couldn't connect to socket with error %i\n", WSAGetLastError());
return 0;
}
//sending request
if (send(s, msg, strlen(msg), 0) == SOCKET_ERROR) {
fprintf(stderr, "Couldn't send request with error %i\n", WSAGetLastError());
return 0;
}
//getting response
size = sizeof(char) * 10240;
response = (char*)malloc(size);
if (recv(s, response, size, 0) == SOCKET_ERROR) {
fprintf(stderr, "Couldn't get response with error %i\n", WSAGetLastError());
return 0;
}
//parsing response
r = (struct routes*)malloc(sizeof(struct routes));
r->statusline = substring(response, indexOf(response, " ", 0)+1, indexOf(response, "\n", 0));
r->version = substring(response, 0, indexOf(response, " ", 0));
r->headers = substring(response, indexOf(response, "\n", 0)+1, indexOf(response, "\n\r", 0)-2);
r->body = substring(response, indexOf(response, "\n\r", 0)+1, strlen(response));
//free varialbes
free(msg);
free(domain);
free(response);
free(resource);
//cleanup
closesocket(s);
WSACleanup();
return r;
}
void response_free(Response r) {
free(r->version);
free(r->statusline);
free(r->headers);
free(r->body);
free(r);
}
/*///////////////////////////////////
Testing:
///////////////////////////////////*/
int main() {
Response r = go("http://help.websiteos.com/websiteos/example_of_a_simple_html_page.htm");
//data, headers, method and port are optional arguments
printf("%s %s\n%s\n\n%s", r->version, r->statusline, r->headers, r->body);
response_free(r);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment