Using D, how would I listen to incoming HTTP reque

2019-03-27 15:58发布

Using D, how would I listen to incoming HTTP traffic and respond to it?

For example (in pseudocode):

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

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

I know there is a lot more to it than that, but I haven't been able to find many resources on responding to incoming http request.

EDIT: My current attempts have yielded only exceptions like "Unable to create socket: Operation not permitted." which may mean I'm doing it correctly but am simply receiving a system error message.

标签: http sockets d
3条回答
一纸荒年 Trace。
2楼-- · 2019-03-27 16:34

it's the same as listening to normal incoming TCP connections and responding to them:

  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));
  }

with handleHttp(Socket) containing the logic for receiving the http request and sending the response as defined be the http standard (you'll have to find that your self though)

查看更多
霸刀☆藐视天下
3楼-- · 2019-03-27 16:37

There's a multi-threaded (event-based) Web server called G-Wan which supports native D scripts.

I never used it with 'D' scripts, only with C++ scripts for which it worked as expected.

查看更多
等我变得足够好
4楼-- · 2019-03-27 16:46

There is currently no HTTP server in the standard library. Adam Ruppe has some very good code on Github for Web work, but it currently doesn't include a standalone Web server.

The program below is a bare-bones, single-threaded basic HTTP server, for educational purposes. Generating a valid HTTP response is still up to you; but at least it parses the header, and gives you a chance to respond based on the details of the request.

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);
}
查看更多
登录 后发表回答