[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Libevent-users] evhttp close callback not invoked when client closes the browser in chunked mode



hello, everyone

i am trying to write a simple comet server with evhttp.

the attached is my code currently compiled and runnable.

but when i visit ip:8811/streaming, and close the browser, the server
side connection callback doesn't invoked.

where in this file it's named HTTPServer::onClose.

can any one tell me how to get the callback when the browser closed?

thanks.
#include <event.h>
#include <evhttp.h>
#include <unistd.h>

#include <iostream>
#include <cassert>
#include <map>

#define MAX 10000

using namespace std;

extern "C" {
  class Push {
  };

  class HTTPServer {
    private:
      struct event_base *base;
      struct evhttp *httpd;
      struct evhttp_bound_socket *handle;

      map<string, evhttp_request *> requests;

      string address;
      int port;

      int token;

    public:
      HTTPServer(string address = "0.0.0.0", int port = 80) {
        base = event_base_new();
        assert(base);
        httpd = evhttp_new(base);
        assert(httpd);
        this->address = address;
        this->port = port;
        int code = evhttp_bind_socket(httpd, address.c_str(), port);
        cout << endl << code << endl;
        this->initCb();
        token = 10000;
      }

      virtual void initHeader(struct evhttp_request *req) {
        evhttp_add_header(req->output_headers, "Server", "Comet Server");
        evhttp_add_header(req->output_headers, "Cache-Control", "no-cache");
        evhttp_add_header(req->output_headers, "Content-Type", "text/plain");

      }

      virtual void initCb() {
        evhttp_set_cb(httpd, "/streaming", HTTPServer::onStreaming, (void *)this);
        evhttp_set_cb(httpd, "/register", HTTPServer::onRegister, (void *)this);
        evhttp_set_cb(httpd, "/notify", HTTPServer::onNotify, (void *)this);
      }

      int getToken();
 
      int sendMessage(struct evhttp_request *req, string message, bool chunked = false);
      static void onCommon(struct evhttp_request *req, void *arg);

      static void onStreaming(struct evhttp_request *req, void *arg);
      static void onRegister(struct evhttp_request *req, void *arg);
      static void onNotify(struct evhttp_request *req, void *arg);

      static void onClose(struct evhttp_connection *con, void *arg);

      void run() {
        cout << "Inside Run" << endl;
        event_base_dispatch(base);
      }

      ~HTTPServer() {
        evhttp_free(httpd);
      }
  };
  
  int HTTPServer::getToken() {
    return token++;
  }

  int HTTPServer::sendMessage(struct evhttp_request *req, string message, bool chunked) {
    struct evbuffer *buf;
    buf = evbuffer_new();
    evbuffer_add_printf(buf, "%s", message.c_str());
    if (!chunked)  {
      evhttp_send_reply(req, HTTP_OK, "OK", buf);
    } else {
      evhttp_send_reply_chunk(req, buf);
    }
  }

  void HTTPServer::onClose(struct evhttp_connection *con, void *arg) {
    cout << " connection closed " << endl;
  }

  void HTTPServer::onRegister(struct evhttp_request *req, void *arg) {
    HTTPServer *server = (HTTPServer *) arg;
    int key = server->getToken();
    cout << key << endl;
    struct evbuffer *buf;
    buf = evbuffer_new();
    evbuffer_add_printf(buf, "%d", key);
    evhttp_send_reply(req, HTTP_OK, "OK", buf);
  }

  void HTTPServer::onNotify(struct evhttp_request *req, void *arg) {
  }

  void HTTPServer::onStreaming(struct evhttp_request *req, void *arg) {
    HTTPServer *server = (HTTPServer *)arg;

    cout << "Inside onComet" << endl;
    const char * uri = evhttp_request_uri(req);

    cout << uri << endl;


    cout << req->kind <<endl;
    server->initHeader(req);
    evhttp_send_reply_start(req, HTTP_OK, "OK");
    evhttp_connection_set_closecb(req->evcon, HTTPServer::onClose, NULL);
    //evhttp_send_reply(req, HTTP_OK, "OK");
    //evhttp_send_reply_chunk(req, buf);
    cout << "Inside onComet end" << endl;
    string a = "hello world from streaming";
    server->sendMessage(req, a, true);
  }

  void HTTPServer::onCommon(struct evhttp_request *req, void *arg) {
    cout << "Inside onCommon" << endl;
    struct evbuffer *buf;
    buf = evbuffer_new();

    cout << req->kind <<endl;

    if (buf == NULL) {
      cerr << "1, failed to create response buffer" << endl;
      cout << "1, failed to create response buffer" << endl;
    }

    evbuffer_add_printf(buf, "{\"now\":%d}", (int)time(NULL));
    evhttp_send_reply(req, HTTP_OK, "OK", buf);
    cout << "Inside onCommon end" << endl;
  }
}

int main() {
  HTTPServer *server = new HTTPServer("0.0.0.0", 8811);
  server->run();
}