<?xml version="1.0" encoding="UTF-8"?>
<codes type="array">
  <code>
    <code>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Collections;

namespace LPT_5.HTTPSocket
{
    class Socket
    {
        private System.Net.Sockets.Socket msSock = null;
        private String msHost = null;
        private int miPort = 80;
        private Hashtable mhHeaders=null;

        public Socket(String sHost, int iPort)
        {
            msHost = sHost;
            miPort = iPort;
            
            //Initialise Standard Headers
            mhHeaders = new Hashtable();
            AddHeader("Connection","Close"); //We wont need to do any pipelining
            AddHeader("Host", sHost);
        }

        public void AddHeader(String sKey, String sValue)
        {
            if(!mhHeaders.ContainsKey(sKey))
                mhHeaders.Add(sKey,sValue);
        }

        private void RemoveHeader(String sKey)
        {
            if(mhHeaders.ContainsKey(sKey))
                mhHeaders.Remove(sKey);
        }

        public String GetURL(String sURL)
        {
            msSock = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            msSock.Connect(msHost, miPort);
            String sReq = "GET " + sURL + " HTTP/1.1";
            sReq = TagHeaders(sReq);
            msSock.Send(System.Text.Encoding.ASCII.GetBytes(sReq));

            Hashtable htHeadParams = new Hashtable();
            int iResult = ReceiveHeader(ref htHeadParams);
            String sBody = null;
            if(htHeadParams.ContainsKey("Content-Length"))
            {
                int iLen = Convert.ToInt32((String)htHeadParams["Content-Length"],10);
                int iOffs = 0;
                byte[] bBuff = new byte[iLen];
                while (iOffs &lt; iLen)
                {
                    iOffs += msSock.Receive(bBuff,iOffs,iLen-iOffs,SocketFlags.None);
                }
                sBody += System.Text.Encoding.ASCII.GetString(bBuff);
            }
            msSock.Close();

            return sBody;
        }

        public byte[] GetRaw(String sURL)
        {
            msSock = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            msSock.Connect(msHost, miPort);
            String sReq = "GET " + sURL + " HTTP/1.1";
            sReq = TagHeaders(sReq);
            msSock.Send(System.Text.Encoding.ASCII.GetBytes(sReq));

            Hashtable htHeadParams = new Hashtable();
            if(ReceiveHeader(ref htHeadParams) == 200) //If we got the data with no problems
            {
                int iLen = Convert.ToInt32((String)htHeadParams["Content-Length"], 10);
                byte[] bBuff = new byte[iLen];
                if (htHeadParams.ContainsKey("Content-Length"))
                {
                    int iOffs = 0;
                    while (iOffs &lt; iLen)
                    {
                        iOffs += msSock.Receive(bBuff, iOffs, iLen - iOffs, SocketFlags.None);
                    }
                }
                msSock.Close();

                return bBuff;
            }
            return null;
        }

        private String TagHeaders(String sReq)
        {
            IDictionaryEnumerator deEnumer = mhHeaders.GetEnumerator();
            while(deEnumer.MoveNext())
            {
                sReq += "\r\n" + deEnumer.Key + ": " + deEnumer.Value;
            }
            return sReq + "\r\n\r\n";
        }

        private int ReceiveHeader(ref Hashtable htHash)
        {
            String sHead = null;
            byte[] buff = new byte[1];

            /*
             We dont know the size of the header, but we do know that header and
             body are separated by a double newline, so read a byte at a time until
             we receive double newline.
            */
            do
            {
                msSock.Receive(buff, 0, 1, SocketFlags.None);
                sHead += (char)buff[0];
            }
            while (!sHead.Contains("\r\n\r\n"));
            int iResult = ProcessHeaders(sHead,ref htHash);

            return iResult;
        }

        private int ProcessHeaders(String sHead, ref Hashtable htHash)
        {
            //Split wont work with \r\n, so just regex away the carriage return
            String sToSplit = Regex.Replace(sHead,"\r","");
            String[] sParams = sToSplit.Split('\n');

            foreach (String sItem in sParams)
            {
                String[] sKeyVal = sItem.Split(':');
                if(sKeyVal.Length &gt;= 2)
                {
                    String sKey = sKeyVal[0].Trim();
                    String sVal = sKeyVal[1].Trim();
                    if (htHash.ContainsKey(sKey))
                        htHash[sKey] += ',' + sVal; //Group multiple headers
                    else
                        htHash.Add(sKey, sVal);
                }
            }

            String[] sResultParams = sParams[0].Split(' ');
            return Convert.ToInt32(sResultParams[1]); //Return the HTTP Response Code
        }
    }
}</code>
    <comment>This is a HTTP socket that I use in one of my projects. It can't handle anything other than 200 OK, but for the purpose it was intended anything other than that should fail anyway, so I don't need proper HTTP response code handling. I'm just hoping really that if there is a way it could be tidied up, sped up or otherwise improved that someone can show how and then learning can happen. My particular problem is reading the header a byte at a time, I am sure there is a better way but such a method escapes me.

Oh and before you say it, I know I can just use WebRequest. If that is your only criticism, please keep it to yourself.</comment>
    <created-at type="datetime">2009-04-05T18:48:01+00:00</created-at>
    <id type="integer">813</id>
    <language>C#</language>
    <permalink>c-socket</permalink>
    <refactors-count type="integer">6</refactors-count>
    <title>C# Socket</title>
    <trackback-url></trackback-url>
    <updated-at type="datetime">2009-10-26T15:47:01+00:00</updated-at>
    <user-id type="integer">1435</user-id>
    <user>
      <id type="integer">1435</id>
      <identity-url>http://teariok.myopenid.com</identity-url>
      <name>teariok.myopenid.com</name>
      <rating type="float">0.0</rating>
      <refactors-count type="integer">1</refactors-count>
      <website nil="true"></website>
    </user>
  </code>
  <code>
    <code>#include &lt;stdlib.h&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;string.h&gt;

// A class to incrementally parse an HTTP header as it comes in. It 
// lets you know when it has received all required bytes, as specified 
// by the content-length header (if present). If there is no content-length,
// it will stop reading after the final "\n\r".
//
// Example usage:
// 
//    HttpParser parser;
//    HttpParser::status_t status;
//
//    for( ;; ) {
//        // read bytes from socket into buffer, break on error
//        status = parser.addBytes( buffer, length );
//        if ( status != HttpParser::Incomplete ) break;
//    }
//
//    if ( status == HttpParser::Done ) {
//        // parse fully formed http message.
//    }


class HttpParser
{
public:
    HttpParser();
    ~HttpParser();

    enum status_t {
        Done,
        Error,
        Incomplete
    };

    status_t addBytes( const char* bytes, unsigned len );

    const char* getMethod();
    const char* getUri();
    const char* getQueryString();
    const char* getBody();
    // key should be in lower case when looking up.
    const char* getValue( const char* key );
    unsigned getContentLength();

private:
    void parseHeader();
    bool parseRequestLine();

    std::string _data;
    unsigned _headerStart;
    unsigned _bodyStart;
    unsigned _parsedTo;
    int _state;
    unsigned _keyIndex;
    unsigned _valueIndex;
    unsigned _contentLength;
    unsigned _contentStart;
    unsigned _uriIndex;
    
    typedef std::vector&lt;unsigned&gt; IntArray;
    IntArray _keys;

    enum State {
        p_request_line=0,
        p_request_line_cr=1,
        p_request_line_crlf=2,
        p_request_line_crlfcr=3,
        p_key=4,
        p_key_colon=5,
        p_key_colon_sp=6,
        p_value=7,
        p_value_cr=8,
        p_value_crlf=9,
        p_value_crlfcr=10,
        p_content=11, // here we are done parsing the header.
        p_error=12 // here an error has occurred and the parse failed.
    };

    status_t _status;
};

HttpParser::HttpParser() :
    _headerStart(0),
    _bodyStart(0),
    _status( Incomplete ),
    _state( 0 ),
    _parsedTo( 0 ),
    _keyIndex(0),
    _valueIndex(0),
    _contentLength(0),
    _contentStart(0),
    _uriIndex(0)
{

}

HttpParser::~HttpParser()
{

}

void
HttpParser::parseHeader()
{
    // run the fsm.
    const int  CR = 13;
    const int  LF = 10;
    const int  ANY = 256;

    enum Action {
        // make lower case
        LOWER = 0x1,

        // convert current character to null.
        NULLIFY = 0x2,

        // set the header index to the current position
        SET_HEADER_START = 0x4,

        // set the key index to the current position
        SET_KEY = 0x8,

        // set value index to the current position.
        SET_VALUE = 0x10,

        // store current key/value pair.
        STORE_KEY_VALUE = 0x20,

        // sets content start to current position + 1
        SET_CONTENT_START = 0x40
    };

    static const struct FSM {
        State curState;
        int c;
        State nextState;
        unsigned actions;
    } fsm[] = {
        { p_request_line,         CR, p_request_line_cr,     NULLIFY                            },
        { p_request_line,        ANY, p_request_line,        0                                  },
        { p_request_line_cr,      LF, p_request_line_crlf,   0                                  },
        { p_request_line_crlf,    CR, p_request_line_crlfcr, 0                                  },
        { p_request_line_crlf,   ANY, p_key,                 SET_HEADER_START | SET_KEY | LOWER },
        { p_request_line_crlfcr,  LF, p_content,             SET_CONTENT_START                  },
        { p_key,                 ':', p_key_colon,           NULLIFY                            },
        { p_key,                 ANY, p_key,                 LOWER                              },
        { p_key_colon,           ' ', p_key_colon_sp,        0                                  },
        { p_key_colon_sp,        ANY, p_value,               SET_VALUE                          },
        { p_value,                CR, p_value_cr,            NULLIFY | STORE_KEY_VALUE          },
        { p_value,               ANY, p_value,               0                                  },
        { p_value_cr,             LF, p_value_crlf,          0                                  },
        { p_value_crlf,           CR, p_value_crlfcr,        0                                  },
        { p_value_crlf,          ANY, p_key,                 SET_KEY | LOWER                    },
        { p_value_crlfcr,         LF, p_content,             SET_CONTENT_START                  },
        { p_error,               ANY, p_error,               0                                  }
    };

    for( unsigned i = _parsedTo; i &lt; _data.length(); ++i) {
        char c = _data[i];
        State nextState = p_error;

        for ( unsigned d = 0; d &lt; sizeof(fsm) / sizeof(FSM); ++d ) {
            if ( fsm[d].curState == _state &amp;&amp; 
                    ( c == fsm[d].c || fsm[d].c == ANY ) ) {

                nextState = fsm[d].nextState;

                if ( fsm[d].actions &amp; LOWER ) {
                    _data[i] = tolower( _data[i] );
                }

                if ( fsm[d].actions &amp; NULLIFY ) {
                    _data[i] = 0;
                }

                if ( fsm[d].actions &amp; SET_HEADER_START ) {
                    _headerStart = i;
                }

                if ( fsm[d].actions &amp; SET_KEY ) {
                    _keyIndex = i;
                }

                if ( fsm[d].actions &amp; SET_VALUE ) {
                    _valueIndex = i;
                }

                if ( fsm[d].actions &amp; SET_CONTENT_START ) {
                    _contentStart = i + 1;
                }

                if ( fsm[d].actions &amp; STORE_KEY_VALUE ) {
                    // store position of first character of key.
                    _keys.push_back( _keyIndex );
                }

                break;
            }
        }

        _state = nextState;

        if ( _state == p_content ) {
            const char* str = getValue("content-length");
            if ( str ) {
                _contentLength = atoi( str );
            }
            break;
        }
    }

    _parsedTo = _data.length();

}

bool
HttpParser::parseRequestLine()
{
    size_t sp1;
    size_t sp2;

    sp1 = _data.find( ' ', 0 );
    if ( sp1 == std::string::npos ) return false;
    sp2 = _data.find( ' ', sp1 + 1 );
    if ( sp2 == std::string::npos ) return false;

    _data[sp1] = 0;
    _data[sp2] = 0;
    _uriIndex = sp1 + 1;
    return true;
}

HttpParser::status_t
HttpParser::addBytes( const char* bytes, unsigned len )
{
    if ( _status != Incomplete ) {
        return _status;
    }

    // append the bytes to data.
    _data.append( bytes, len );

    if ( _state &lt; p_content ) {
        parseHeader();
    }

    if ( _state == p_error ) {
        _status = Error;
    } else if ( _state == p_content ) {
        if ( _contentLength == 0 || _data.length() - _contentStart &gt;= _contentLength ) {
            if ( parseRequestLine() ) {
                _status = Done;
            } else {
                _status = Error;
            }
        }
    }

    return _status;
}

const char*
HttpParser::getMethod()
{
    return &amp;_data[0];
}

const char*
HttpParser::getUri()
{
    return &amp;_data[_uriIndex];
}

const char*
HttpParser::getQueryString()
{
    const char* pos = getUri();
    while( *pos ) {
        if ( *pos == '?' ) {
            pos++;
            break;
        }
        pos++;
    }
    return pos;
}

const char* 
HttpParser::getBody()
{
    if ( _contentLength &gt; 0 ) {
        return &amp;_data[_contentStart];
    } else  {
        return NULL;
    }
}

// key should be in lower case.
const char* 
HttpParser::getValue( const char* key )
{
    for( IntArray::iterator iter = _keys.begin();
            iter != _keys.end(); ++iter  )
    {
        unsigned index = *iter;
        if ( strcmp( &amp;_data[index], key ) == 0 ) {
            return &amp;_data[index + strlen(key) + 2];
        }

    }

    return NULL;
}

unsigned
HttpParser::getContentLength()
{
    return _contentLength;
}
</code>
    <comment>I'm writing a web server, and I'm particularly proud of this HTTP parser. One difficulty with HTTP is the web server doesn't know when to stop reading the HTTP request from the socket until it receives the content-length value. This class solves that problem. You keep feeding it bytes until it returns the HttpParser::Done or HttpParser::Error status. 

It also breaks the header up into key-values pairs in-place, so the whole header and data is kept in one string. When you request a value, it just returns a pointer to the value. </comment>
    <created-at type="datetime">2009-03-09T22:48:57+00:00</created-at>
    <id type="integer">778</id>
    <language>C++</language>
    <permalink>an-efficient-http-parser</permalink>
    <refactors-count type="integer">2</refactors-count>
    <title>An efficient HTTP parser</title>
    <trackback-url></trackback-url>
    <updated-at type="datetime">2009-09-11T22:32:39+00:00</updated-at>
    <user-id type="integer">1390</user-id>
    <user>
      <id type="integer">1390</id>
      <identity-url>http://steve.hanov.myopenid.com</identity-url>
      <name>steve.hanov.myopenid.com</name>
      <rating type="float">0.0</rating>
      <refactors-count type="integer">1</refactors-count>
      <website>http://gandolf.homelinux.org/~smhanov/blog</website>
    </user>
  </code>
  <code>
    <code>#!/usr/bin/python

import socket,time

testdns = 'google.com'
print "Testing connection with",testdns 
while(True):
    try:
        connected = True
        socket.gethostbyname(testdns)
    except socket.gaierror: 
        connected = False
    if(not connected):
        print "Not Connected..."
        print "\a", ; time.sleep(.1); print "\a",
    else:
        print "Connected..."
        print "\a",
    time.sleep(2)

</code>
    <comment>This is a Quick and Dirty script that beeps once when it is connected to the internet and twice when it fails. The idea is to let me know if the computer is still connected while I am bent over backward, under the desk across the room, screwing with the cables. </comment>
    <created-at type="datetime">2008-10-02T01:06:20+00:00</created-at>
    <id type="integer">515</id>
    <language>Python</language>
    <permalink>connection-detection-script</permalink>
    <refactors-count type="integer">3</refactors-count>
    <title>Connection Detection script</title>
    <trackback-url></trackback-url>
    <updated-at type="datetime">2009-02-27T04:50:39+00:00</updated-at>
    <user-id type="integer">1051</user-id>
    <user>
      <id type="integer">1051</id>
      <identity-url>http://matthew.scouten.myopenid.com</identity-url>
      <name>matthew.scouten.myopenid.com</name>
      <rating type="float">0.0</rating>
      <refactors-count type="integer">0</refactors-count>
      <website nil="true"></website>
    </user>
  </code>
  <code>
    <code>int socket_read_line_alloc(int sock, char** out) {
        /* current buffer size */
        unsigned int size = 128;
        /* current location in buffer */
        int i = 0;
        /* whether the previous char was a \r */
        int cr = 0;
        char ch;

        /* result, grows as we need it to */
        *out = malloc(sizeof(char) * size);

        for ( ; ; ) {
                if (recv(sock, &amp;ch, 1, 0) == -1) {
                        return -1;
                }

                if (i &gt;= size) {
                        /* grow buffer */
                        size *= 2;
                        *out = realloc(*out, size);
                }

                if (ch == '\n') {
                        /* if preceded by a \r, we overwrite it */
                        if (cr) {
                                assert(i &gt; 0);
                                i--;
                        }

                        (*out)[i] = '\0';
                        break;

                } else {
                        cr = (ch == '\r' ? 1 : 0);
                        (*out)[i] = ch;
                }

                i++;
        }

        return i + 1;
}

</code>
    <comment>I don't like the char** out, it just feels ugly to me. But seeing as I have to return a -1 for a socket error, else the string length, it seems to be the only way. Unless I switch the result and out so I return the char* and write the size/status to an output argument. Thoughts? Also, comments on the actual algorithm are appreciated.</comment>
    <created-at type="datetime">2007-12-06T22:13:14+00:00</created-at>
    <id type="integer">174</id>
    <language>C</language>
    <permalink>socket-read-line-in-c</permalink>
    <refactors-count type="integer">5</refactors-count>
    <title>Socket read line in C</title>
    <trackback-url></trackback-url>
    <updated-at type="datetime">2009-11-03T19:03:29+00:00</updated-at>
    <user-id type="integer">398</user-id>
    <user>
      <id type="integer">398</id>
      <identity-url>http://bugmenot2.myopenid.com</identity-url>
      <name>bugmenot2.myopenid.com</name>
      <rating type="float">0.0</rating>
      <refactors-count type="integer">0</refactors-count>
      <website nil="true"></website>
    </user>
  </code>
</codes>
