Esempio n. 1
0
 public function SetCookie($cookie)
 {
     if (!isset($cookie["domain"]) || !isset($cookie["path"]) || !isset($cookie["name"]) || !isset($cookie["value"])) {
         return array("success" => false, "error" => \CubicleSoft\HTTP::HTTPTranslate("SetCookie() requires 'domain', 'path', 'name', and 'value' to be options."), "errorcode" => "missing_information");
     }
     $cookie["domain"] = strtolower($cookie["domain"]);
     if (substr($cookie["domain"], 0, 1) != ".") {
         $cookie["domain"] = "." . $cookie["domain"];
     }
     $cookie["path"] = str_replace("\\", "/", $cookie["path"]);
     if (substr($cookie["path"], -1) != "/") {
         $cookie["path"] = "/";
     }
     if (!isset($this->data["cookies"][$cookie["domain"]])) {
         $this->data["cookies"][$cookie["domain"]] = array();
     }
     if (!isset($this->data["cookies"][$cookie["domain"]][$cookie["path"]])) {
         $this->data["cookies"][$cookie["domain"]][$cookie["path"]] = array();
     }
     $this->data["cookies"][$cookie["domain"]][$cookie["path"]][] = $cookie;
     return array("success" => true);
 }
 public function Wait($timeout = false, $readfps = array(), $writefps = array(), $exceptfps = NULL)
 {
     $this->UpdateStreamsAndTimeout("", $timeout, $readfps, $writefps);
     $result = array("success" => true, "clients" => array(), "removed" => array(), "readfps" => array(), "writefps" => array(), "exceptfps" => array());
     if (!count($readfps) && !count($writefps)) {
         return $result;
     }
     $result2 = self::FixedStreamSelect($readfps, $writefps, $exceptfps, $timeout);
     if ($result2 === false) {
         return array("success" => false, "error" => \CubicleSoft\HTTP::HTTPTranslate("Wait() failed due to stream_select() failure.  Most likely cause:  Connection failure."), "errorcode" => "stream_select_failed");
     }
     // Handle new connections.
     if (isset($readfps["http_s"])) {
         while (($fp = @stream_socket_accept($this->fp, 0)) !== false) {
             // Enable non-blocking mode.
             stream_set_blocking($fp, 0);
             $client = $this->InitNewClient();
             $client->fp = $fp;
             $client->ipaddr = stream_socket_get_name($fp, true);
         }
         unset($readfps["http_s"]);
     }
     // Handle clients in the read queue.
     foreach ($readfps as $cid => $fp) {
         if (!is_string($cid) || strlen($cid) < 6 || substr($cid, 0, 7) !== "http_c_") {
             continue;
         }
         $id = (int) substr($cid, 7);
         if (!isset($this->clients[$id])) {
             continue;
         }
         $client = $this->clients[$id];
         $client->lastts = microtime(true);
         if ($client->httpstate !== false) {
             $result2 = \CubicleSoft\HTTP::ProcessState($client->httpstate);
             if ($result2["success"]) {
                 // Trigger the last variable to process when extracting form variables.
                 if ($client->contenttype !== false && $client->contenttype[""] === "application/x-www-form-urlencoded") {
                     $this->ProcessClientRequestBody($result2["request"], "&", $id);
                 }
                 if ($client->currfile !== false) {
                     $client->files[$client->currfile]->Close();
                     $client->currfile = false;
                 }
                 $result["clients"][$id] = $client;
                 $client->requestcomplete = true;
                 $client->requests++;
                 $client->mode = "init_response";
                 $client->responseheaders = array();
                 $client->responsefinalized = false;
                 $client->responsebodysize = false;
                 $client->httpstate["type"] = "request";
                 $client->httpstate["startts"] = microtime(true);
                 $client->httpstate["waituntil"] = -1.0;
                 $client->httpstate["data"] = "";
                 $client->httpstate["bodysize"] = false;
                 $client->httpstate["chunked"] = false;
                 $client->httpstate["secure"] = $this->ssl;
                 $client->httpstate["state"] = "send_data";
                 $client->SetResponseCode(200);
                 $client->SetResponseContentType("text/html; charset=UTF-8");
                 if (isset($client->headers["Connection"])) {
                     $connection = \CubicleSoft\HTTP::ExtractHeader($client->headers["Connection"]);
                     if (strtolower($connection[""]) === "close") {
                         $client->keepalive = false;
                     }
                 }
                 $ver = explode("/", $client->request["httpver"]);
                 $ver = (double) array_pop($ver);
                 if ($ver < 1.1) {
                     $client->keepalive = false;
                 }
                 if ($client->requests >= $this->maxrequests) {
                     $client->keepalive = false;
                 }
                 if ($this->usegzip && isset($client->headers["Accept-Encoding"])) {
                     $encodings = \CubicleSoft\HTTP::ExtractHeader($client->headers["Accept-Encoding"]);
                     $encodings = explode(",", $encodings[""]);
                     $gzip = false;
                     foreach ($encodings as $encoding) {
                         if (strtolower(trim($encoding)) === "gzip") {
                             $gzip = true;
                         }
                     }
                     if ($gzip) {
                         $client->deflate = new \CubicleSoft\DeflateStream();
                         $client->deflate->Init("wb", -1, array("type" => "gzip"));
                         $client->AddResponseHeader("Content-Encoding", "gzip", true);
                     }
                 }
             } else {
                 if ($result2["errorcode"] !== "no_data") {
                     if ($client->requests) {
                         $result["removed"][$id] = array("result" => $result2, "client" => $client);
                     }
                     $this->RemoveClient($id);
                 } else {
                     if ($client->requestcomplete === false && $client->httpstate["state"] !== "request_line" && $client->httpstate["state"] !== "headers") {
                         // Allows the caller an opportunity to adjust some client options based on inputs on a per-client basis (e.g. recvlimit).
                         $result["clients"][$id] = $client;
                     }
                 }
             }
         }
         unset($readfps[$cid]);
     }
     // Handle clients in the write queue.
     foreach ($writefps as $cid => $fp) {
         if (!is_string($cid) || strlen($cid) < 6 || substr($cid, 0, 7) !== "http_c_") {
             continue;
         }
         $id = (int) substr($cid, 7);
         if (!isset($this->clients[$id])) {
             continue;
         }
         $client = $this->clients[$id];
         $client->lastts = microtime(true);
         if ($client->httpstate !== false) {
             // Transform the client response into real data.
             if ($client->mode === "response_ready") {
                 if ($client->responsefinalized) {
                     $client->AddResponseHeader("Content-Length", (string) strlen($client->writedata), true);
                     $client->httpstate["bodysize"] = strlen($client->writedata);
                 } else {
                     if ($client->responsebodysize !== false) {
                         $client->AddResponseHeader("Content-Length", (string) $client->responsebodysize, true);
                         $client->httpstate["bodysize"] = $client->responsebodysize;
                     } else {
                         if ($client->keepalive) {
                             $client->AddResponseHeader("Transfer-Encoding", "chunked", true);
                             $client->httpstate["chunked"] = true;
                         }
                     }
                 }
                 $client->AddResponseHeader("Date", gmdate("D, d M Y H:i:s T"), true);
                 if (!$client->keepalive || $client->requests >= $this->maxrequests) {
                     $client->AddResponseHeader("Connection", "close", true);
                 }
                 foreach ($client->responseheaders as $name => $vals) {
                     foreach ($vals as $val) {
                         $client->httpstate["data"] .= $name . ": " . $val . "\r\n";
                     }
                 }
                 $client->responseheaders = false;
                 $client->httpstate["data"] .= "\r\n";
                 $client->mode = "handle_response";
             }
             $result2 = \CubicleSoft\HTTP::ProcessState($client->httpstate);
             if ($result2["success"]) {
                 if (!$client->responsefinalized) {
                     $result["clients"][$id] = $client;
                 } else {
                     if ($client->keepalive && $client->requests < $this->maxrequests) {
                         // Reset client.
                         $client->mode = "init_request";
                         $client->httpstate = false;
                         $client->readdata = "";
                         $client->request = false;
                         $client->url = "";
                         $client->headers = false;
                         $client->contenttype = false;
                         $client->contenthandled = true;
                         $client->cookievars = false;
                         $client->requestvars = false;
                         $client->requestcomplete = false;
                         $client->deflate = false;
                         $client->writedata = "";
                         foreach ($client->files as $filename => $tempfile) {
                             unset($client->files[$filename]);
                         }
                         $client->files = array();
                         $this->initclients[$id] = $client;
                         unset($this->clients[$id]);
                     } else {
                         $result["removed"][$id] = array("result" => array("success" => true), "client" => $client);
                         $this->RemoveClient($id);
                     }
                 }
             } else {
                 if ($result2["errorcode"] !== "no_data") {
                     $result["removed"][$id] = array("result" => $result2, "client" => $client);
                     $this->RemoveClient($id);
                 }
             }
         }
         unset($writefps[$cid]);
     }
     // Initialize new clients.
     foreach ($this->initclients as $id => $client) {
         do {
             $origmode = $client->mode;
             switch ($client->mode) {
                 case "init":
                     $result2 = $this->ssl ? @stream_socket_enable_crypto($client->fp, true, STREAM_CRYPTO_METHOD_TLS_SERVER) : true;
                     if ($result2 === true) {
                         $client->mode = "init_request";
                     } else {
                         if ($result2 === false) {
                             @fclose($client->fp);
                             unset($this->initclients[$id]);
                         }
                     }
                     break;
                 case "init_request":
                     // Use the HTTP class in server mode to handle state.
                     // The callback functions are located in WebServer to avoid the issue of pass-by-reference memory leaks.
                     $options = $this->defaultclientoptions;
                     $options["async"] = true;
                     $options["read_headers_callback"] = array($this, "ProcessClientRequestHeaders");
                     $options["read_headers_callback_opts"] = $id;
                     $options["read_body_callback"] = array($this, "ProcessClientRequestBody");
                     $options["read_body_callback_opts"] = $id;
                     $options["write_body_callback"] = array($this, "ProcessClientResponseBody");
                     $options["write_body_callback_opts"] = $id;
                     if (!isset($options["readlinelimit"])) {
                         $options["readlinelimit"] = 116000;
                     }
                     if (!isset($options["maxheaders"])) {
                         $options["maxheaders"] = 1000;
                     }
                     if (!isset($options["recvlimit"])) {
                         $options["recvlimit"] = 1000000;
                     }
                     $startts = microtime(true);
                     $timeout = isset($options["timeout"]) ? $options["timeout"] : false;
                     $result2 = array("success" => true, "rawsendsize" => 0, "rawsendheadersize" => 0, "rawrecvsize" => 0, "rawrecvheadersize" => 0, "startts" => $startts);
                     $debug = isset($options["debug"]) && $options["debug"];
                     if ($debug) {
                         $result2["rawsend"] = "";
                         $result2["rawrecv"] = "";
                     }
                     $client->httpstate = \CubicleSoft\HTTP::InitResponseState($client->fp, $debug, $options, $startts, $timeout, $result2, false, false);
                     $client->mode = "handle_request";
                     $client->lastts = microtime(true);
                     $this->clients[$id] = $client;
                     unset($this->initclients[$id]);
                     break;
             }
         } while (isset($this->initclients[$id]) && $origmode !== $client->mode);
     }
     // Handle client timeouts.
     $ts = microtime(true);
     foreach ($this->clients as $id => $client) {
         if ($client->lastts + $this->defaultclienttimeout < $ts) {
             if ($client->requests) {
                 $result["removed"][$id] = array("result" => $result2, "client" => $client);
             }
             $this->RemoveClient($id);
         }
     }
     // Return any extra handles that were being waited on.
     $result["readfps"] = $readfps;
     $result["writefps"] = $writefps;
     $result["exceptfps"] = $exceptfps;
     return $result;
 }