Posts Tagged: c


6
Apr 06

Reverse proxy servers

I have been reading on the Hypertext Transfer Protocol (HTTP). The simplicity of information exchange between an HTTP server and an HTTP client amazes me: besides the encapsulation done for a TCP connection, all other information sent is in a fairly simple format. To request for the page at http://google.com, for instance, the client may just send the following line to the server:

GET http://google.com HTTP/1.1

Then, upon receiving a request, a server may just send back:

HTTP/1.1 200 OK
Content-Type: text/html

Content goes here.

The World Wide Web Consortium (W3C) defines standards for HTTP request and response packets.

Now, what is the place of a regular proxy server in all this? If an HTTP client is connected to the Internet without having to pass through a proxy server, the request is traditionally sent to TCP port 80 of the web host, and the proxy server is the one that produces the response. After a little experimentation, I learned that if a proxy server is involved, the only difference is that the same request is sent to the specified port of the proxy server instead of the port of the web server – the request is sent as it is. The following code is a rather dirty and simple implementation of a reverse proxy that will return a default page for HTTP requests for any web page:

/*
 * reverse-proxy-server.c
 *
 * Responds with default data upon receiving an HTTP request for any web page
 *
 * USAGE:
 *   reverse-proxy-server
 *
 * LIMITATIONS:
 * 1. This script does not make use of a separate configuration file, and not
 * include proper signal handling.
 * 2. This script assumes that all information received are HTTP requests. For
 * information on the format of valid HTTP requests, visit
 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html.
 */

#include 
#include 
#include 
#include 
#include 

#define DEFAULT_PORT 3128
#define MAXIMUM_CLIENT_NUMBER 256
#define MAXIMUM_MESSAGE_LENGTH 256

int main(int argc, char *argv[]) {
    int server_socket, client_socket, port, sockaddr_in_length, pid;
    struct sockaddr_in server_address, client_address;
    char buffer[256];

    sockaddr_in_length = sizeof(struct sockaddr_in);

    // Create the server socket
    if ((server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        perror("Error creating socket.");
        return 1;
    }

    // Set up the server address
    memset((void *) &server_address, 0, sockaddr_in_length);
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(DEFAULT_PORT);

    // Bind the socket to an address
    if (bind(server_socket, (struct sockaddr *) &server_address, sockaddr_in_length) < 0) {
        perror("Error binding socket.");
        return 1;
    }

    // Listen for connections
    listen(server_socket, MAXIMUM_CLIENT_NUMBER);

    while (1) {
        printf("Listening for a connection...n");

        // Accept connection
        if ((client_socket = accept(server_socket, (struct sockaddr *) &client_address, &sockaddr_in_length))

< 0) {
            perror("Error accepting incoming socket connection.");
            return 1;
        }

        printf("Accepted connection.n");

        pid = fork();

        if (pid == 0) {
            printf("Reading HTTP request...n");

            // Receive HTTP request from the client
            bzero(buffer, MAXIMUM_MESSAGE_LENGTH);
            read(client_socket, buffer, MAXIMUM_MESSAGE_LENGTH);
            printf("%sn", buffer);

            printf("Sending HTTP response...n");

            // Send HTTP reply to the client
            bzero(buffer, MAXIMUM_MESSAGE_LENGTH);
            strcpy(buffer, "HTTP-Version: HTTP/1.1 200 OKnContent-Type:

text/htmlnContent-Length: 18nnContent goes here.");
            write(client_socket, buffer, MAXIMUM_MESSAGE_LENGTH);

            printf("Successful.n");

            // Close socket connection
            close(client_socket);

            return 0;
        }
    }

    return 0;
}

Play around with the code if you are interested. To see this work on localhost:

  1. Compile the code using gcc.
    $ gcc -o reverse-proxy-server reverse-proxy-server.c
  2. Run the reverse proxy server.
    $ ./reverse-proxy-server
  3. Open your web browser.
  4. Set the HTTP proxy for your browser to localhost, and set the corresponding port number to 3128.
  5. Try to access any web page through your browser.

It is amazing. Once the general idea of the protocol has been grasped, simple web servers are not too difficult to conceptualize.


15
Mar 06

manpages-dev

For all else who are having a difficult time trying to find out what the name of the package (the standard Debian packages, at least) for manuals on C system calls and library functions is, it is manpages-dev.

Happy hacking!