Created
May 10, 2010 19:33
-
-
Save jarsen/396423 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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