2011-10-04 15 views
7

Usando D, ¿cómo podría escuchar el tráfico HTTP entrante y responder a él?Usando D, ¿cómo podría escuchar las solicitudes HTTP entrantes y responder a ellas?

Por ejemplo (en pseudocódigo):

socket = new socket("locahost", 80) 
socket.onRequestRecevied(handleRequest); 

function response handleRequest(request) { 
    //do something with the request and respond 
    request.respond("hello world") 
} 

Sé que hay mucho más que eso, pero no he sido capaz de encontrar muchos recursos en respuesta a la solicitud HTTP entrante.

EDIT: Mis intentos actuales han producido solo excepciones como "No se ha podido crear el socket: operación no permitida". lo que puede significar que lo estoy haciendo correctamente, pero estoy recibiendo un mensaje de error del sistema.

+0

¿Tiene permiso para escuchar en el puerto 80 o en cualquier otro puerto de bajo nivel? Pruebe con el puerto 8080 o alguna otra cosa que no esté en el rango restringido. – gmfawcett

+0

Lo estaba intentando con el puerto 3000. También lo probé con 8080 y algunos otros. –

Respuesta

5

que es lo mismo que escuchar a las conexiones normales TCP entrante y responder a ellas:

import std.socket; 
    Socket s = new TcpSocket(AddressFamily.INET); 
    s.bind(new InternetAddress("0.0.0.0", 80)); 
    s.listen(8); 
    while (true) { 
    Socket conn=s.accept(); 
    //handle incoming message (I'm putting it in a task pool to handle ;)) 
    taskPool.put(task!handleHttp(conn)); 
    } 

con handleHttp(Socket) que contiene la lógica para la recepción de la solicitud HTTP y enviar la respuesta como se define el estándar http (usted tiene que encontrarlo usted mismo)

+0

Esto parece estar funcionando ahora. Gracias. –

5

Actualmente no hay un servidor HTTP en la biblioteca estándar. Adam Ruppe tiene para trabajar en la web, pero actualmente no incluye un servidor web independiente.

El siguiente programa es un servidor HTTP básico simple de una sola hebra, para fines educativos . Generar una respuesta HTTP válida depende de usted; pero al menos analiza el encabezado y le da la oportunidad de responder en función de los detalles de de la solicitud.

import std.algorithm; 
import std.conv; 
import std.stdio; 
import std.socket; 
import std.string; 

// usage: ./server port 

void main(string[] args) 
{ 
    enum BACKLOG = 8; 
    ushort PORT = to!ushort(args[1]); 
    Socket s = new TcpSocket(AddressFamily.INET); 
    s.bind(new InternetAddress("0.0.0.0", PORT)); 
    s.listen(BACKLOG); 

    scope (exit) 
    { 
    s.shutdown(SocketShutdown.BOTH); 
    s.close(); 
    } 

    while (true) 
    { 
    debug writeln("waiting..."); 
    Socket conn = s.accept(); 
    scope (exit) 
    { 
     conn.shutdown(SocketShutdown.BOTH); 
     conn.close(); 
    } 
    try 
    { 
     handleHttp(conn); 
    } 
    catch (Throwable e) 
    { 
     stderr.writeln("thrown: ", e); 
    } 
    }  
} 

void handleHttp(Socket conn) 
{ 
    // Make a buffer big enough to read a full HTTP header. My approach here is to 
    // read the header in its entirety before proceeding. This isn't production 
    // quality, but good enough for some applications. 

    ubyte[8192] buf; // big enough for some purposes... 
    size_t position, headerEnd, len, newpos; 

    // Receive the whole header before parsing it. 
    while (true) 
    { 
    len = conn.receive(buf[position..$]); 

    if (len == 0)    // empty request 
     return; 

    newpos = position + len; 
    headerEnd = countUntil(buf[position..newpos], "\r\n\r\n"); 
    position = newpos; 

    if (headerEnd >= 0) 
     break; 
    } 

    // Anything beyond headerEnd+4 is part of the request body. For now, bail: 
    // no POSTs or PUTs allowed. Feel free to remove the assert & implement them! 
    assert (position-(headerEnd+4) == 0, 
      "Sorry, only content-free requests are supported."); 

    // Now parse the header. 
    auto lines   = splitter(buf[0..headerEnd], "\r\n"); 
    string request_line = cast(string) lines.front; 
    lines.popFront; 

    debug writeln(request_line); 

    // a very simple Header structure. 
    struct Pair 
    { 
    string key, value; 

    this(ubyte[] line) 
    { 
     auto tmp = countUntil(line, ": "); 
     key  = cast(string) line[0..tmp]; // maybe down-case these? 
     value  = cast(string) line[tmp+2..$]; 
    } 
    } 

    Pair[] headers; 
    foreach(line; lines) 
    headers ~= Pair(line); 

    auto tmp  = splitter(request_line, ' '); 
    string method = tmp.front; tmp.popFront; 
    string url  = tmp.front; tmp.popFront; 
    string protocol = tmp.front; tmp.popFront; 

    debug writefln("%s, %s, %s", method, url, protocol); 

    // Prepare a response, and send it 

    string resp = join(["HTTP/1.1 200 OK", 
         "Content-Length: 2", 
         "Content-Type: text/plain", 
         "Connection: close", 
         "", 
         "OK"], 
        "\r\n"); 

    conn.send(cast(ubyte[]) resp); 
} 
+0

¡Gracias! ¿No sabes cómo hacerlo multihilo? –

1

Hay un servidor (basada en eventos) Web multi-hilo llamado G-Wan que apoya secuencias de comandos nativos D.

Nunca lo usé con scripts 'D', solo con scripts en C++ para los que funcionó como se esperaba.

Cuestiones relacionadas