Skip to content

Instantly share code, notes, and snippets.

@jarsen
Created May 10, 2010 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jarsen/396423 to your computer and use it in GitHub Desktop.
Save jarsen/396423 to your computer and use it in GitHub Desktop.
// Author: Jason Larsen
// Project: A program that downloads a webpage using an HTTP GET request. I probably
// will never use this because I'll just use curl -I anyway... but it was fun
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SOCKET_ERROR -1
#define LARGE_BUFFER 4096
#define HOST_NAME_SIZE 255
#define HOST argv[argc - 3]
#define PORT argv[argc - 2]
#define PATH argv[argc - 1]
void fatal(char *message) {
char error_message[100];
strcpy(error_message, "[!!] Fatal Error ");
strncat(error_message, message, 83);
perror(error_message);
exit(-1);
}
int send_string(int sockfd, unsigned char *buffer) {
int sent_bytes, bytes_to_send;
bytes_to_send = strlen(buffer);
while(bytes_to_send > 0) {
sent_bytes = send(sockfd, buffer, bytes_to_send, 0);
if(sent_bytes == -1)
return 0; // return 0 on send error
bytes_to_send -= sent_bytes;
buffer += sent_bytes;
}
return 1; // return 1 on success
}
int recv_line(int sockfd, unsigned char *dest_buffer) {
#define EOL "\r\n" // End-Of-Line byte sequence
#define EOL_SIZE 2
unsigned char *ptr;
int eol_matched = 0;
ptr = dest_buffer;
while(recv(sockfd, ptr, 1, 0) == 1) { // read a single byte
if(*ptr == EOL[eol_matched]) { // does this byte match terminator
eol_matched++;
if(eol_matched == EOL_SIZE) { // if all bytes match terminator,
*(ptr+1-EOL_SIZE) = '\0'; // terminate the string
return strlen(dest_buffer); // return bytes recevied
}
} else {
eol_matched = 0;
}
ptr++; // increment the pointer to the next byter;
}
return 0; // didn't find the end of line characters
}
// Reads in an HTTP header, filling the buffer passed in and returning
// the number of bytes (Content-Length) that should be read
int recv_header(int sockfd, unsigned char *dest_buffer) {
int bytes_to_recv = 0;
char buffer[LARGE_BUFFER];
while(recv_line(sockfd, buffer)) {
strncat(dest_buffer, buffer, strlen(buffer));
strncat(dest_buffer, "\n", 1);
if(strncasecmp(buffer, "Content-Length:", 15) == 0) {
// copy into dest_buffer
bytes_to_recv = atoi(buffer+15);
}
}
return bytes_to_recv;
}
void usage(char * program_name) {
printf("Usage: %s [-d] <hostname> <port> <path>\n", program_name);
exit(1);
}
int main(int argc, char *argv[]) {
int sockfd, port;
struct hostent *host_info;
struct in_addr *address;
struct sockaddr_in target_addr;
int recv_length=1, yes=1;
unsigned char buffer[LARGE_BUFFER];
int dflag = 0;
// USAGE and param checking
int ch;
while((ch = getopt(argc, argv, "d:")) != -1)
if(ch == 'd') dflag = 1;
else usage(argv[0]);
if( argc - dflag != 4 ) usage(argv[0]); // make sure we have either 4 or 5
int i; // make sure we're getting a valid port
for(i = 0; PORT[i]; i++)
if(!isnumber(PORT[i])) usage(argv[0]);
port = atoi(PORT);
if((host_info = gethostbyname(HOST)) == NULL)
fatal("looking up hostname");
if ((sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
fatal("Making socket");
// is this only for when you're binding?
// if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
// fatal("setting socket option SO_REUSEADDR");
target_addr.sin_family = AF_INET;
target_addr.sin_port = htons(port);
target_addr.sin_addr = *((struct in_addr *)host_info->h_addr);
memset(&(target_addr.sin_zero), '\0', 8); // zero the rest of the struct
// send GET request
if (connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr)) == -1)
fatal("connecting to target server");
char request[100];
strcpy(request,"GET ");
strncat(request,PATH,strlen(PATH));
strncat(request," HTTP/1.0\r\n\r\n",13);
printf("%s\n", request);
if(!send_string(sockfd, request))
fatal("sending GET REQUEST");
int bytes_to_recv = recv_header(sockfd, buffer);
if(dflag) printf("%s\n",buffer);
// if(bytes_to_recv == 0) fatal("no Content-Length tag or value of 0");
if(bytes_to_recv == 0) bytes_to_recv = 1024;
char body[bytes_to_recv + 1];
int bytes_read;
while((bytes_read = recv(sockfd, body, bytes_to_recv, 0)) > 0) {
// printf("bytes read: %d", bytes_read);
body[bytes_read] = '\0';
printf("%s\n", body);
}
close(sockfd);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment