예제 #1
0
파일: FS.php 프로젝트: ruslanchek/phpdaemon
 public static function readfileChunked($path, $cb, $chunkcb, $pri = EIO_PRI_DEFAULT)
 {
     if (!FS::$supported) {
         call_user_func($chunkcb, $path, $r = readfile($path));
         call_user_func($cb, $r !== false);
         return;
     }
     FS::open($path, 'r', function ($file) use($cb, $chunkcb, $pri) {
         if (!$file) {
             call_user_func($cb, $path, false);
         }
         $file->readAllChunked($cb, $chunkcb, $pri);
     }, null, $pri);
 }
예제 #2
0
 /**
  * Parse request body
  * @return void
  */
 public function parseStdin()
 {
     do {
         if ($this->boundary === false) {
             break;
         }
         $continue = false;
         if ($this->mpartstate === self::MPSTATE_SEEKBOUNDARY) {
             // seek to the nearest boundary
             if (($p = strpos($this->attrs->stdinbuf, $ndl = '--' . $this->boundary . "\r\n", $this->mpartoffset)) !== false) {
                 // we have found the nearest boundary at position $p
                 $this->mpartoffset = $p + strlen($ndl);
                 $this->mpartstate = self::MPSTATE_HEADERS;
                 $continue = true;
             }
         } elseif ($this->mpartstate === self::MPSTATE_HEADERS) {
             // parse the part's headers
             $this->mpartcondisp = false;
             if (($p = strpos($this->attrs->stdinbuf, "\r\n\r\n", $this->mpartoffset)) !== false) {
                 // we got all of the headers
                 $h = explode("\r\n", binarySubstr($this->attrs->stdinbuf, $this->mpartoffset, $p - $this->mpartoffset));
                 $this->mpartoffset = $p + 4;
                 $this->attrs->stdinbuf = binarySubstr($this->attrs->stdinbuf, $this->mpartoffset);
                 $this->mpartoffset = 0;
                 for ($i = 0, $s = sizeof($h); $i < $s; ++$i) {
                     $e = explode(':', $h[$i], 2);
                     $e[0] = strtr(strtoupper($e[0]), HTTPRequest::$htr);
                     if (isset($e[1])) {
                         $e[1] = ltrim($e[1]);
                     }
                     if ($e[0] == 'CONTENT_DISPOSITION' && isset($e[1])) {
                         parse_str(strtr($e[1], HTTPRequest::$hvaltr), $this->mpartcondisp);
                         if (!isset($this->mpartcondisp['form-data'])) {
                             break;
                         }
                         if (!isset($this->mpartcondisp['name'])) {
                             break;
                         }
                         $this->mpartcondisp['name'] = trim($this->mpartcondisp['name'], '"');
                         $name = $this->mpartcondisp['name'];
                         if (isset($this->mpartcondisp['filename'])) {
                             $this->mpartcondisp['filename'] = trim($this->mpartcondisp['filename'], '"');
                             if (!ini_get('file_uploads')) {
                                 break;
                             }
                             $this->attrs->files[$name] = array('name' => $this->mpartcondisp['filename'], 'type' => '', 'tmp_name' => '', 'error' => UPLOAD_ERR_OK, 'size' => 0);
                             $tmpdir = ini_get('upload_tmp_dir');
                             if ($tmpdir === false) {
                                 $this->attrs->files[$name]['fp'] = false;
                                 $this->attrs->files[$name]['error'] = UPLOAD_ERR_NO_TMP_DIR;
                             } else {
                                 $this->attrs->files[$name]['tmp_name'] = FS::tempnam($tmpdir, 'php');
                                 if ($this->oldFashionUploadFP) {
                                     $this->attrs->files[$name]['fp'] = fopen($this->attrs->files[$name]['tmp_name'], 'c+');
                                 } else {
                                     $req = $this;
                                     if (FS::$supported) {
                                         $this->conn->lockRead();
                                     }
                                     FS::open($this->attrs->files[$name]['tmp_name'], 'c+', function ($fp) use($req, $name) {
                                         if (!$fp) {
                                             $req->attrs->files[$name]['error'] = UPLOAD_ERR_CANT_WRITE;
                                         }
                                         $req->attrs->files[$name]['fp'] = $fp;
                                         if (FS::$supported) {
                                             $req->conn->unlockRead();
                                         }
                                     });
                                 }
                             }
                             $this->mpartstate = self::MPSTATE_UPLOAD;
                         } else {
                             $this->attrs->post[$this->mpartcondisp['name']] = '';
                         }
                     } elseif ($e[0] == 'CONTENT_TYPE' && isset($e[1])) {
                         if (isset($this->mpartcondisp['name']) && isset($this->mpartcondisp['filename'])) {
                             $this->attrs->files[$this->mpartcondisp['name']]['type'] = $e[1];
                         }
                     }
                 }
                 if ($this->mpartstate === self::MPSTATE_HEADERS) {
                     $this->mpartstate = self::MPSTATE_BODY;
                 }
                 $continue = true;
             }
         } elseif ($this->mpartstate === self::MPSTATE_BODY || $this->mpartstate === self::MPSTATE_UPLOAD) {
             // process the body
             if (($p = strpos($this->attrs->stdinbuf, $ndl = "\r\n--" . $this->boundary . "\r\n", $this->mpartoffset)) !== false || ($p = strpos($this->attrs->stdinbuf, $ndl = "\r\n--" . $this->boundary . "--\r\n", $this->mpartoffset)) !== false) {
                 // we have the whole Part in buffer
                 $chunk = binarySubstr($this->attrs->stdinbuf, $this->mpartoffset, $p - $this->mpartoffset);
                 if ($this->mpartstate === self::MPSTATE_BODY && isset($this->mpartcondisp['name'])) {
                     $this->attrs->post[$this->mpartcondisp['name']] .= $chunk;
                 } elseif ($this->mpartstate === self::MPSTATE_UPLOAD && isset($this->mpartcondisp['filename'])) {
                     if (!isset($this->attrs->files[$this->mpartcondisp['name']]['fp'])) {
                         return;
                         // fd is not ready yet, interrupt
                     }
                     if ($fp = $this->attrs->files[$this->mpartcondisp['name']]['fp']) {
                         if ($this->oldFashionUploadFP) {
                             fwrite($fp, $chunk);
                         } else {
                             $fp->write($chunk);
                         }
                     }
                     $this->attrs->files[$this->mpartcondisp['name']]['size'] += $p - $this->mpartoffset;
                 }
                 if ($ndl === "\r\n--" . $this->boundary . "--\r\n") {
                     // end of whole message
                     $this->mpartoffset = $p + strlen($ndl);
                     $this->mpartstate = self::MPSTATE_SEEKBOUNDARY;
                     $this->stdin_done = true;
                 } else {
                     $this->mpartoffset = $p;
                     $this->mpartstate = self::MPSTATE_HEADERS;
                     // let's read the next part
                     $continue = true;
                 }
                 $this->attrs->stdinbuf = binarySubstr($this->attrs->stdinbuf, $this->mpartoffset);
                 $this->mpartoffset = 0;
             } else {
                 // we have only piece of Part in buffer
                 $p = strlen($this->attrs->stdinbuf) - strlen($ndl);
                 if ($p !== false) {
                     $chunk = binarySubstr($this->attrs->stdinbuf, $this->mpartoffset, $p - $this->mpartoffset);
                     if ($this->mpartstate === self::MPSTATE_BODY && isset($this->mpartcondisp['name'])) {
                         $this->attrs->post[$this->mpartcondisp['name']] .= $chunk;
                     } elseif ($this->mpartstate === self::MPSTATE_UPLOAD && isset($this->mpartcondisp['filename'])) {
                         if (!isset($this->attrs->files[$this->mpartcondisp['name']]['fp'])) {
                             return;
                             // fd is not ready yet, interrupt
                         }
                         if ($fp = $this->attrs->files[$this->mpartcondisp['name']]['fp']) {
                             if ($this->oldFashionUploadFP) {
                                 fwrite($fp, $chunk);
                             } else {
                                 $fp->write($chunk);
                             }
                         }
                         $this->attrs->files[$this->mpartcondisp['name']]['size'] += $p - $this->mpartoffset;
                         if ($this->parseSize(ini_get('upload_max_filesize')) < $this->attrs->files[$this->mpartcondisp['name']]['size']) {
                             $this->attrs->files[$this->mpartcondisp['name']]['error'] = UPLOAD_ERR_INI_SIZE;
                         }
                         if (isset($this->attrs->post['MAX_FILE_SIZE']) && $this->attrs->post['MAX_FILE_SIZE'] < $this->attrs->files[$this->mpartcondisp['name']]['size']) {
                             $this->attrs->files[$this->mpartcondisp['name']]['error'] = UPLOAD_ERR_FORM_SIZE;
                         }
                     }
                     $this->mpartoffset = $p;
                     $this->attrs->stdinbuf = binarySubstr($this->attrs->stdinbuf, $this->mpartoffset);
                     $this->mpartoffset = 0;
                 }
             }
         }
     } while ($continue);
 }
예제 #3
0
 /**
  * Called when new data received.
  * @return void
  */
 public function onRead()
 {
     start:
     $buf = $this->read($this->readPacketSize);
     if ($this->state === self::STATE_ROOT) {
         if (strlen($buf) === 0) {
             return;
         }
         if (strpos($buf, "<policy-file-request/>") !== false) {
             if (($FP = FlashPolicyServer::getInstance()) && $FP->policyData) {
                 $this->write($FP->policyData . "");
             }
             $this->finish();
             return;
         }
         $rid = ++Daemon::$process->reqCounter;
         $this->state = self::STATE_HEADERS;
         $req = new stdClass();
         $req->attrs = new stdClass();
         $req->attrs->request = array();
         $req->attrs->get = array();
         $req->attrs->post = array();
         $req->attrs->cookie = array();
         $req->attrs->server = array();
         $req->attrs->files = array();
         $req->attrs->session = null;
         $req->attrs->id = $rid;
         $req->attrs->params_done = false;
         $req->attrs->stdin_done = false;
         $req->attrs->stdinbuf = '';
         $req->attrs->stdinlen = 0;
         $req->attrs->inbuf = '';
         $req->attrs->chunked = false;
         $req->queueId = $rid;
         $req->conn = $this;
         $this->req = $req;
     } else {
         if (!$this->req) {
             Daemon::log('Unexpected input (HTTP request).');
             return;
         }
         $req = $this->req;
     }
     if ($this->state === self::STATE_HEADERS) {
         $req->attrs->inbuf .= $buf;
         $buf = '';
         if (($p = strpos($req->attrs->inbuf, "\r\n\r\n")) !== false) {
             $headers = binarySubstr($req->attrs->inbuf, 0, $p);
             $headersArray = explode("\r\n", $headers);
             $req->attrs->inbuf = binarySubstr($req->attrs->inbuf, $p + 4);
             $command = explode(' ', $headersArray[0]);
             $u = isset($command[1]) ? parse_url($command[1]) : false;
             if ($u === false) {
                 $this->badRequest($req);
                 return;
             }
             $req->attrs->server['REQUEST_METHOD'] = $command[0];
             $req->attrs->server['REQUEST_TIME'] = time();
             $req->attrs->server['REQUEST_TIME_FLOAT'] = microtime(true);
             $req->attrs->server['REQUEST_URI'] = $u['path'] . (isset($u['query']) ? '?' . $u['query'] : '');
             $req->attrs->server['DOCUMENT_URI'] = $u['path'];
             $req->attrs->server['PHP_SELF'] = $u['path'];
             $req->attrs->server['QUERY_STRING'] = isset($u['query']) ? $u['query'] : null;
             $req->attrs->server['SCRIPT_NAME'] = $req->attrs->server['DOCUMENT_URI'] = isset($u['path']) ? $u['path'] : '/';
             $req->attrs->server['SERVER_PROTOCOL'] = isset($command[2]) ? $command[2] : 'HTTP/1.1';
             list($req->attrs->server['REMOTE_ADDR'], $req->attrs->server['REMOTE_PORT']) = explode(':', $this->addr);
             for ($i = 1, $n = sizeof($headersArray); $i < $n; ++$i) {
                 $e = explode(': ', $headersArray[$i]);
                 if (isset($e[1])) {
                     $req->attrs->server['HTTP_' . strtoupper(strtr($e[0], HTTPRequest::$htr))] = $e[1];
                 }
             }
             if (isset($u['host'])) {
                 $req->attrs->server['HTTP_HOST'] = $u['host'];
             }
             $req->attrs->params_done = true;
             if (isset($req->attrs->server['HTTP_CONNECTION']) && preg_match('~(?:^|\\W)Upgrade(?:\\W|$)~i', $req->attrs->server['HTTP_CONNECTION']) && isset($req->attrs->server['HTTP_UPGRADE']) && strtolower($req->attrs->server['HTTP_UPGRADE']) === 'websocket') {
                 if ($this->pool->WS) {
                     $this->pool->WS->inheritFromRequest($req, $this->pool);
                     return;
                 } else {
                     $this->finish();
                     return;
                 }
             } else {
                 $req = Daemon::$appResolver->getRequest($req, $this->pool, isset($this->pool->config->responder->value) ? $this->pool->config->responder->value : null);
                 $req->conn = $this;
                 $this->req = $req;
             }
             if ($req instanceof stdClass) {
                 $this->endRequest($req, 0, 0);
             } else {
                 if ($this->pool->config->sendfile->value && (!$this->pool->config->sendfileonlybycommand->value || isset($req->attrs->server['USE_SENDFILE'])) && !isset($req->attrs->server['DONT_USE_SENDFILE'])) {
                     $fn = FS::tempnam($this->pool->config->sendfiledir->value, $this->pool->config->sendfileprefix->value);
                     $req->sendfp = FS::open($fn, 'wb');
                     $req->header('X-Sendfile: ' . $fn);
                 }
                 $buf = $req->attrs->inbuf;
                 $req->attrs->inbuf = '';
                 $this->state = self::STATE_CONTENT;
             }
         } else {
             return;
             // not enough data
         }
     }
     if ($this->state === self::STATE_CONTENT) {
         $req->stdin($buf);
         $buf = '';
         if ($req->attrs->stdin_done) {
             $this->state = self::STATE_ROOT;
         } else {
             return;
         }
     }
     if ($req->attrs->stdin_done && $req->attrs->params_done) {
         if ($this->pool->variablesOrder === null) {
             $req->attrs->request = $req->attrs->get + $req->attrs->post + $req->attrs->cookie;
         } else {
             for ($i = 0, $s = strlen($this->pool->variablesOrder); $i < $s; ++$i) {
                 $char = $this->pool->variablesOrder[$i];
                 if ($char == 'G') {
                     $req->attrs->request += $req->attrs->get;
                 } elseif ($char == 'P') {
                     $req->attrs->request += $req->attrs->post;
                 } elseif ($char == 'C') {
                     $req->attrs->request += $req->attrs->cookie;
                 }
             }
         }
         Daemon::$process->timeLastReq = time();
     } else {
         goto start;
     }
 }
예제 #4
0
 /**
  * Open logs.
  * @return void
  */
 public static function openLogs()
 {
     if (Daemon::$config->logging->value) {
         Daemon::$logpointer = fopen(Daemon::$config->logstorage->value, 'a');
         if (isset(Daemon::$config->group->value)) {
             chgrp(Daemon::$config->logstorage->value, Daemon::$config->group->value);
             // @TODO: rewrite to async I/O
         }
         if (isset(Daemon::$config->user->value)) {
             chown(Daemon::$config->logstorage->value, Daemon::$config->user->value);
             // @TODO: rewrite to async I/O
         }
         if (Daemon::$process instanceof Daemon_WorkerThread && FS::$supported) {
             FS::open(Daemon::$config->logstorage->value, 'a!', function ($file) {
                 Daemon::$logpointerAsync = $file;
                 if (!$file) {
                     return;
                 }
             });
         }
     } else {
         Daemon::$logpointer = null;
         Daemon::$logpointerAsync = null;
     }
 }