/ / メモ
2009-08-13

HTTP/0.9 用のクライアントを書いた。
サイトによってはレスポンスヘッダが帰ってくる。

次は、1.0を実装してみよう。

private import std.socket;
private import std.string;
private import std.regex;
private import std.conv;

struct URI
{
    string scheme;
    string host;
    string port;
    string path;
    string query;
    string fragment;

    this(string uri)
    {
        auto r = regex(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?","g");
        foreach (m; match(uri, r))
        {
            if(m.pmatch[2].startIdx != -1) scheme = m.input[m.pmatch[2].startIdx .. m.pmatch[2].endIdx];
            if(m.pmatch[4].startIdx != -1)
            {
                int len = m.input[m.pmatch[4].startIdx .. m.pmatch[4].endIdx].indexOf(":");
                if(len != -1)
                {
                    host = m.input[m.pmatch[4].startIdx .. m.pmatch[4].startIdx + len];
                    port = m.input[m.pmatch[4].startIdx + len + 1 .. m.pmatch[4].endIdx];
                }else{
                    host = m.input[m.pmatch[4].startIdx .. m.pmatch[4].endIdx];
                }
            }
            if(m.pmatch[5].startIdx != -1) path = m.input[m.pmatch[5].startIdx .. m.pmatch[5].endIdx];
            if(m.pmatch[7].startIdx != -1) query = m.input[m.pmatch[7].startIdx .. m.pmatch[7].endIdx];
            if(m.pmatch[9].startIdx != -1) fragment = m.input[m.pmatch[9].startIdx .. m.pmatch[9].endIdx];
        }
    }

    const string toString()
    {
        string s;

        if(scheme) s ~= scheme ~ ":";
        if(host) s ~= "//" ~ host;
        if(port) s ~= ":" ~ port;
        if(path)
        {
             s ~= path;
        }else{
             s ~= "/";
        }
        if(query) s ~= "?" ~ query;
        if(fragment) s ~= "#" ~ fragment;

        return s;
    }
}

class HttpClient
{
  private:
    TcpSocket socket;
    string httpVersion;

  public:
    this(string httpVersion)
    {
        switch(httpVersion)
        {
            case "HTTP/0.9":
                this.httpVersion = httpVersion;
                break;
            default:
                new Exception("HTTPVersion not supported");
        }
    }

    byte[] get(in string uri)
    {
        switch(httpVersion)
        {
            case "HTTP/0.9":
                URI u = URI(uri);
                ushort port = 80;
                if(u.port) port = to!(ushort)(u.port);
                auto ia = new InternetAddress(u.host,port);
                socket = new TcpSocket(ia);
                string req = "GET " ~ u.path ~ "\r\n";
                socket.send(req);

                int read;
                byte[] recv;
                byte[1024] buf;

                while((read = socket.receive(buf)) > 0)
                {
                    recv ~= buf[0 .. read];
                }
                return recv;
            default:
                new Exception("HTTPVersion not supported");
        }
    }

    byte[] get(in string uri,in string proxy)
    {
        switch(httpVersion)
        {
            case "HTTP/0.9":
                URI u = URI(uri);
                URI p = URI(proxy);
                if(p.port) port = to!(ushort)(p.port);
                auto ia = new InternetAddress(p.host,port);
                socket = new TcpSocket(ia);

                string req = "GET " ~ u.toString ~ "\r\n";
                int sent;
                sent = socket.send(req);
                if(sent == -1)
                {
                    throw new Exception("error socket send");
                }

                int read;
                byte[] recv;
                byte[1024] buf;

                while((read = socket.receive(buf)) > 0)
                {
                    recv ~= buf[0 .. read];
                }
                if(read == -1)
                {
                    throw new Exception("error socket recive");
                }
                return recv;
            default:
                new Exception("HTTPVersion not supported");
        }
    }
}

使い方

auto client = new HttpClient("HTTP/0.9");
byte[] recv = client.get("http://example.com/");
write(cast(char[])recv);

トラックバック http://mikanya.dip.jp/memo/2009-08-13-1