Используя D, как я буду прослушивать входящие HTTP-запросы и отвечать на них? - PullRequest
7 голосов
/ 04 октября 2011

Используя D, как бы я слушал входящий HTTP-трафик и отвечал на него?

Например (в псевдокоде):

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

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

Я знаю, что это намного большекроме этого, но я не смог найти много ресурсов при ответе на входящий HTTP-запрос.

РЕДАКТИРОВАТЬ: мои текущие попытки привели только к исключениям, как «Невозможно создать сокет: операция не разрешена».это может означать, что я делаю это правильно, но просто получаю системное сообщение об ошибке.

Ответы [ 3 ]

5 голосов
/ 05 октября 2011

В стандартной библиотеке нет HTTP-сервера.У Adam Ruppe есть некоторый очень хороший код на Github для веб-работы, но в настоящее время он не включает автономный веб-сервер.

Программа, представленная ниже, представляет собой простой однопоточныйHTTP-сервер, в образовательных целях.Создание правильного HTTP-ответа все еще зависит от вас;но, по крайней мере, он анализирует заголовок и дает вам возможность ответить на основании деталей запроса.

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);
}
5 голосов
/ 05 октября 2011

это то же самое, что слушать обычные входящие TCP-соединения и отвечать на них:

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

с handleHttp(Socket), содержащим логику для получения http-запроса и отправки ответа в соответствии со стандартом http (Вы должны найти это сами, хотя)

1 голос
/ 03 февраля 2012

Существует многопоточный (основанный на событиях) веб-сервер с именем G-Wan , который поддерживает собственные D скрипты.

Я никогда не использовал его со сценариями 'D', только со сценариями C ++, для которых он работал должным образом.

...