Roxen.git / server / protocols / http.pike

version» Context lines:

Roxen.git/server/protocols/http.pike:17:   #define TIMER_PREFIX "http:"   #include <timers.h>      inherit RequestID;      #ifdef PROFILE   #define HRTIME() gethrtime()   int req_time = HRTIME();   #endif    + #define WEBSOCKET_DEBUG +  + #ifdef WEBSOCKET_DEBUG + #define WS_DEBUG werror + #else + #define WS_DEBUG(X...) + #endif /* WEBSOCKET_DEBUG */ +    #ifdef REQUEST_DEBUG   int footime, bartime;   #define REQUEST_WERR(X) do { \    if (this) { \    bartime = gethrtime()-footime; \    werror("%s (%d)\n", (X), bartime); \    footime=gethrtime(); \    } else { \    werror("%s\n", (X)); \    } \
Roxen.git/server/protocols/http.pike:1482:    xml_data = 0;    request_uuid = UNDEFINED;   }      void end(int|void keepit)   {    if (my_fd) {    CHECK_FD_SAFE_USE;    }    +  if (websocket) { +  websocket->end(); +  websocket = 0; +  } +     cleanup_request_object();       if(keepit    && !file->raw    && misc->connection != "close"    && my_fd    // Is this necessary now when this function no longer is called    // from the close callback? /mast    && !catch(my_fd->query_address()) )    { -  +  if (file->upgrade_websocket) { + #ifdef CONNECTION_DEBUG +  werror("HTTP[%s]: Transitioning to WebSocket ------------------------\n", +  DEBUG_GET_FD); + #else +  REQUEST_WERR("HTTP: Transitioning to WebSocket."); + #endif +  websocket = WebSocket(this, file->websocket_api, leftovers); +  websocket->masking = file->masking; +  my_fd = 0; +  pipe = 0; +  return; +  }    // Now.. Transfer control to a new http-object. Reset all variables etc..    object o = object_program(this_object())(0, 0, 0);    o->remoteaddr = remoteaddr;       // Don't share these since proxies can send different user-agent headers    // when multiplexing several clients into one connection    //o->client = client;    //o->supports = supports;    //o->client_var = client_var;   
Roxen.git/server/protocols/http.pike:2025:    conf->log(file, this_object());       json_logger->log(([    "event" : "LOG_REQUEST",    "htime" : handle_time,    "qtime" : queue_time,    "rtime" : gethrtime()-hrtime,    ]));    }    } +     if( !port_obj )    {    TIMER_END(do_log);    MERGE_TIMERS(conf);    if( conf )    conf->connection_drop( this_object() );    call_out (disconnect, 0);    return;    }    TIMER_END(do_log);
Roxen.git/server/protocols/http.pike:3001: Inside #if defined(HTTP_COMPRESSION)
   }    }       if(file->compressed && misc->etag) {    string etag = misc->etag;    if(etag[sizeof(etag)-1..] == "\"")    misc->etag = etag[..sizeof(etag)-2] + ";gzip\"";    }   #endif    +  if ((method != "HEAD") && (undefinedp(file->len) || (file->len < 0)) && +  (misc->connection == "keep-alive")) { +  // Unknown length ==> Connection: close. +  if (file->file) { +  variant_heads->Connection = "close"; +  misc->connection = "close"; +  } else if (!file->data) { +  file->data = ""; +  file->len = 0; +  } +  } +     if (file->error == 200) {    int conditional;    if (none_match) {    // NOTE: misc->etag may be zero below, but that's ok.    if (none_match[misc->etag] || (misc->etag && none_match["*"])) {    // We have a if-none-match header that matches our etag.    if ((<"HEAD", "GET">)[method]) {    // RFC 2616 14.26:    // Instead, if the request method was GET or HEAD, the server    // SHOULD respond with a 304 (Not Modified) response, including
Roxen.git/server/protocols/http.pike:3087:    file->data = "";    file->file = 0;    } else {   #ifdef HTTP_COMPRESSION    if(misc->etag)    variant_heads["ETag"] = misc->etag;    if(file->encoding)    variant_heads["Content-Encoding"] = file->encoding;    // Perhaps set some gzip log status if file->encoding == "gzip" here?   #endif +  if ((method != "HEAD") && (undefinedp(file->len) || (file->len < 0)) && +  (misc->connection == "keep-alive")) { +  // Unknown length ==> Connection: close. +  variant_heads->Connection = "close"; +  misc->connection = "close"; +  }    if (misc->range) {    // Handle byte ranges.    int skip;    string if_range;    if (if_range = request_headers["if-range"]) {    // Check If-Range header (RFC 2068 14.27).    if (has_prefix(if_range, "\"")) {    // ETag    if (if_range != misc->etag) {    // ETag has changed.
Roxen.git/server/protocols/http.pike:3172:    }       handle_request();       }) {    call_out (disconnect, 0);    report_error("Internal server error: " + describe_backtrace(err));    }   }    + //! Set to a @[WebSocket] object if this connection is upgraded to a + //! websocket. + object websocket; +  + //! Call this method to send a text frame across the websocket + //! connection. + //! + //! @returns 1 if this isn't an open websocket connection. + public int websocket_send_text(string text) { +  if (!websocket || +  websocket->state != Protocols.WebSocket.Connection.OPEN) { +  return 1; +  } +  +  websocket->send_text(text); +  return 0; + } +  + //! Call this method to send a binary frame across the websocket + //! connection. + //! + //! @returns 1 if this isn't an open websocket connection. + public int websocket_send_binary(string data) { +  if (!websocket || +  websocket->state != Protocols.WebSocket.Connection.OPEN) { +  return 1; +  } +  +  websocket->send_binary(data); +  return 0; + } +  +  +    void handle_request()   {    if (mixed err = catch {       REQUEST_WERR("HTTP: handle_request()");    TIMER_START(handle_request);    json_logger->log(([    "event" : "HANDLE_REQUEST_BEGIN",    "qtime" : queue_time,    ]));   #ifdef TIMERS   #define LOG_HANDLE_END() do { json_logger->log((["event" : "HANDLE_REQUEST_END", "handle_time" : timers->handle_request ])); } while(0)   #else   #define LOG_HANDLE_END()   #endif    -  +    #ifdef MAGIC_ERROR    if(prestate->old_error)    {    array err = get_error(variables->error, variables->error_md5 || "NONE");    if(err && arrayp(err))    {    if(prestate->plain)    {    file = ([    "type":"text/plain",
Roxen.git/server/protocols/http.pike:3232:    }   #endif /* MAGIC_ERROR */       MARK_FD("HTTP handling request");       handle_time = gethrtime();   #if constant(System.CPU_TIME_IS_THREAD_LOCAL)    handle_vtime = gethrvtime();   #endif    +  // Protect against asynchronous self desctruction. +  object json_logger = this::json_logger; + #ifdef TIMERS +  mapping(string:int) timers = this::timers; + #endif +     mapping result;    array e = catch(result = conf->handle_request( this_object() ));    // Note: Could be destructed here already since handle_request might    // have handed over us to another thread that finished quickly. The    // right place to put code is probably send_result instead.    //    // I wonder exactly where that handing-over might happen. There    // should probably be destruct_threadbound_session_objects calls    // there too. /mast       if (this)    destruct_threadbound_session_objects();       if(e)    INTERNAL_ERROR( e );       else { -  +  if (result && result->upgrade_websocket) { +  REQUEST_WERR("HTTP: handle_request: Preparing for upgrade to websocket.\n"); +  +  if (method != Roxen.WEBSOCKET_OPEN_METHOD) { +  error("Invalid attempt to upgrade to websocket.\n"); +  } +  +  Protocols.WebSocket.Request ws_req = Protocols.WebSocket.Request(0); +  ws_req->request_headers = request_headers; +  +  mapping(string:string) ws_headers = ([]); + #if constant(Protocols.WebSocket.Extension) +  array ws_extensions = ({}); +  [ws_headers, ws_extensions] = +  ws_req->low_websocket_accept(result->websocket_protocol, +  result->websocket_extensions); +  result->parsed_websocket_extensions = ws_extensions; + #else +  ws_headers = ws_req->low_websocket_accept(result->websocket_protocol); + #endif +  +  REQUEST_WERR(sprintf("HTTP: ws_headers: %O\n", ws_headers)); +  +  result->extra_heads += ws_headers; +  misc->connection = "Upgrade"; +  +  NO_PROTO_CACHE(); +  +  REQUEST_WERR("HTTP: handle_request: socket prepared for upgrade.\n"); +  } +     if (result && result->pipe) {    REQUEST_WERR("HTTP: handle_request: pipe in progress.");    TIMER_END(handle_request); -  +  // NB: Request may already be completed and we may have been desctructed. +  // Local copys of json_logger and timers (see above) saves us from +  // suffering from trying to use objects in desctructed object.    json_logger->log(([    "event" : "PIPE_BEGIN",    ]));    LOG_HANDLE_END();    return;    }    file = result;    }       if( file && file->try_again_later )