diff --git a/c/httphead/Makefile b/c/httphead/Makefile new file mode 100644 index 0000000..a94da74 --- /dev/null +++ b/c/httphead/Makefile @@ -0,0 +1,7 @@ +all: httphead + +httphead: httphead.c + $(CC) $(CFLAGS) $^ -o httphead + +clean: + rm -f httphead diff --git a/c/httphead/httphead.c b/c/httphead/httphead.c new file mode 100644 index 0000000..0c869f1 --- /dev/null +++ b/c/httphead/httphead.c @@ -0,0 +1,313 @@ +/* + * httphead - show http header of a website + */ + +/* + * Copyright (c) 2006 Andreas Jaggi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +#include "httphead.h" + +const char usagemsg[] = + "usage: httphead [-r] [-q] [-p port] [-s host-] [-d path] [-s host] URL\n" + "\n" + "options:\n" + " -p port use this port instead of 80\n" + " -s host use this host instead of the one specified in the URL\n" + " -d path use this path instead of the one specified in the URL\n" + " -r show sent request\n" + " -q show only the recieved status code\n" + " also: -v show version\n" + " -h display this help\n" + " -l display (BSD) license\n" + ; + +void usage ( ); + +void crlf ( int s ); + +char* gethost ( char* url ); +char* getpath ( char* url ); +char* getstatuscode ( char* response ); + +int main ( int argc, char* argv[] ) { + + int tmp; + char* hend = NULL; + char buff[HH_BUFFSIZE+1]; + + char* url = NULL; + + char* host = NULL; + char* path = NULL; + int port = 80; + + int showrequest = 0; + int statuscodeonly = 0; + char* statuscode = NULL; + + struct hostent *remote_hostent = NULL; + struct sockaddr_in *remote_host_addr = NULL; + + int sock; + + while ( (tmp = getopt(argc, argv, "qrd:s:p:hlv")) != -1 ) { + switch ( tmp ) { + case 'h': + usage(); + exit(0); + case 'l': + license(); + exit(0); + case 'v': + version(); + exit(0); + case 'p': + port = atoi(optarg); + break; + case 's': + host = optarg; + break; + case 'd': + path = optarg; + break; + case 'q': + statuscodeonly = 1; + break; + case 'r': + showrequest = 1; + break; + } + } + + if ( optind >= argc ) { + usage(); + exit(0); + } + + url = argv[optind]; + + if ( path == NULL ) { + path = getpath(url); + } + + if ( host == NULL ) { + host = gethost(url); + } + + remote_hostent = gethostbyname(host); + + if ( remote_hostent == NULL ) { + herror(NULL); + exit(-1); + } + + remote_host_addr = alloca(sizeof(struct sockaddr_in)); + remote_host_addr->sin_family = AF_INET; + remote_host_addr->sin_addr = *((struct in_addr*) remote_hostent->h_addr); + remote_host_addr->sin_port = port; + + if ( (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) { + showerror("socket"); + exit(-1); + } + + if ( connect(sock, (struct sockaddr*)remote_host_addr, sizeof(struct sockaddr_in)) == -1 ) { + showerror("connect"); + exit(-1); + } + + + /* main */ + + if ( showrequest ) { + write(1, "GET ", 4); + write(1, path, strlen(path)); + write(1, " HTTP/1.0", 9); + crlf(1); + write(1, "Host: ", 6); + write(1, host, strlen(host)); + + crlf(1); + crlf(1); + + write(1, "Response:\n\n", 12); + } + + write(sock, "GET ", 4); + write(sock, path, strlen(path)); + write(sock, " HTTP/1.0", 9); + crlf(sock); + write(sock, "Host: ", 6); + write(sock, host, strlen(host)); + + crlf(sock); + crlf(sock); + + while ( (tmp = recv(sock, buff, HH_BUFFSIZE, 0)) > 0 ) { + buff[tmp] = '\0'; + + if ( (hend = strstr(buff, "\x0D\x0A\x0D\x0A")) != NULL) { + tmp = hend-buff; + *hend = '\n'; + *(hend+1) = '\0'; + } + + if ( statuscodeonly ) { + if ( (statuscode = getstatuscode(buff)) != NULL ) { + write(1, statuscode, 3); + write(1, "\n", 1); + break; + } + } else { + write(1, buff, tmp); + } + + if ( hend != NULL ) { + break; + } + } + + if ( shutdown(sock, 2) == -1 ) { + showerror("shutdown"); + exit(-1); + } + + if ( close(sock) == -1 ) { + showerror("close"); + exit(-1); + } + + exit(0); +} + +char* _gethoststart ( char* url ) { + char* s = NULL; + + s = strstr(url, "http://"); + if ( s == NULL ) { + s = strstr(url, "https://"); + if ( s == NULL ) { + s = url; // assume that there is no http[s]:// prefix + } else { + s += 8; + } + } else { + s += 7; + } + + if ( s >= url + strlen(url) ) { + return url; + } + + return s; +} + +int _gethostlen ( char* s ) { + int e = 0; + + while ( *(s+e) != '/' && *(s+e) != '?' && *(s+e) != '\0' ) { + e++; + } + + return e; +} + +char* getstatuscode ( char* s ) { + char* htp = NULL; + + if ( (htp = strstr(s, "HTTP/")) != NULL ) { + while ( *htp != '\0' && *htp != ' ' ) { + htp++; + } + + while ( *htp == ' ' ) { + htp++; + } + + if ( *htp == '\0' ) { + htp = NULL; + } + } + + return htp; +} + +char* getpath ( char* url ) { + char* s = NULL; + int e; + + s = _gethoststart(url); + + e = _gethostlen(s); + + s += e; + + if ( s >= url+strlen(url) ) { + s = (char*)malloc(2*sizeof(char)); + *s = '/'; + *(s+1) = '\0'; + } + + return s; +} + +char* gethost ( char* url ) { + char* s = NULL; + char* r = NULL; + int e = 0; + + s = _gethoststart(url); + + e = _gethostlen(s); + + if ( e == 0 ) { + return NULL; + } + + r = (char*)malloc(sizeof(char)*(e+1)); + + memcpy(r, s, e); + + r[e+1] = '\0'; + + return r; +} + +void crlf ( int s ) { + write(s, "\x0D\x0A", 2); +} + +void usage ( ) { + write(1, usagemsg, strlen(usagemsg)); +} diff --git a/c/httphead/httphead.h b/c/httphead/httphead.h new file mode 100644 index 0000000..f01cacc --- /dev/null +++ b/c/httphead/httphead.h @@ -0,0 +1,55 @@ +#ifndef _HTTPHEAD_H +#define _HTTPHEAD_H + +#define HH_BUFFSIZE 512 + +#include +#include +#include + +const char licensemsg[] = + "httphead is copyright (c) 2006 Andreas Jaggi \n" + "All rights reserved.\n" + "\n" + "Redistribution and use in source and binary forms, with or without\n" + "modification, are permitted provided that the following conditions\n" + "are met:\n" + "1. Redistributions of source code must retain the above copyright\n" + " notice, this list of conditions and the following disclaimer.\n" + "2. Redistributions in binary form must reproduce the above copyright\n" + " notice, this list of conditions and the following disclaimer in the\n" + " documentation and/or other materials provided with the distribution.\n" + "3. The name of the author may not be used to endorse or promote products\n" + " derived from this software without specific prior written permission.\n" + "\n" + "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" + "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" + "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" + "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" + "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n" + "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" + "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" + "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" + "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n" + "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + ; + +const char versionmsg[] = "httphead 0.2\n"; + +void license ( ) { + write(1, licensemsg, strlen(licensemsg)); +} + +void version ( ) { + write(1, versionmsg, strlen(versionmsg)); +} + +void showerror ( char* type ) { + char* errstr = strerror(errno); + write(2, type, strlen(type)); + write(2, ": ", 2); + write(2, errstr, strlen(errstr)); + write(2, "\n", 1); +} + +#endif