Beispiel #1
0
 public function __construct($request = null, $data = null)
 {
     //start stream handler
     $this->stream = Stream::receive($request);
     //store request
     $this->request = $this->stream->decode();
     //store data
     $this->request_data = $data;
     //start logging
     $this->log = Log::_get()->setLevel(Log::WARN)->setLabel('Xport-Resp');
 }
Beispiel #2
0
 public static function process($xp, $crypt = null)
 {
     Validate::prime($xp->get());
     Validate::go('action')->not('blank')->is('al');
     Validate::paint();
     $stream = Stream::receive($xp->getRequestData(), $crypt);
     $fileio = static::_get();
     switch ($xp->get('action')) {
         case static::FILE_IO_READ:
             //validate request
             Validate::prime($xp->get());
             Validate::go('path')->not('blank');
             Validate::go('offset')->is('num');
             Validate::go('length')->is('num');
             Validate::paint();
             //setup and read
             $fileio->setPath($xp->get('path'));
             $fileio->setOffset($xp->get('offset'));
             $data = $fileio->read($xp->get('length'));
             $sha1 = sha1($data);
             $md5 = md5($data);
             //tune data
             $stream->setPayload($sha1 . $md5 . $data);
             //pass data back
             return $xp->addResponseData($stream->encode());
             break;
         case static::FILE_IO_WRITE:
             //validate request
             Validate::prime($xp->get());
             Validate::go('path')->not('blank');
             Validate::go('offset')->is('num');
             Validate::paint();
             //validate payload
             $data = $stream->decode();
             $sha1 = substr($data, 0, 40);
             $md5 = substr($data, 40, 32);
             $data = substr($data, 72);
             if (sha1($data) !== $sha1) {
                 throw new Exception('Payload hash mismatch (sha1) block could not be written');
             }
             if (md5($data) !== $md5) {
                 throw new Exception('Payload hash mismatch (md5) block could not be written');
             }
             //Setup and write
             $fileio->setPath($xp->get('path'));
             $fileio->setOffset($xp->get('offset'));
             if (($bytes_written = $fileio->write($data)) === false) {
                 throw new Exception('Failed to write block');
             }
             //pass success
             return $xp->add('bytes_written', $bytes_written);
             break;
         case static::FILE_IO_RCOPY:
             //validate request
             Validate::prime($xp->get());
             Validate::go('path')->not('blank');
             Validate::go('offset')->is('num');
             Validate::go('remote_path')->not('blank');
             Validate::go('remote_offset')->is('num');
             Validate::go('remote_length')->is('num');
             Validate::paint();
             //setup and copy
             $fileio->setPath($xp->get('path'));
             $fileio->setOffset($xp->get('offset'));
             if (!($bytes_written = $fileio->rcopy($xp->get('remote_path'), $xp->get('remote_offset'), $xp->get('remote_length')))) {
                 throw new Exception('Failed to copy from remote file');
             }
             //pass success
             return $xp->add('bytes_written', $bytes_written);
             break;
         case static::FILE_IO_STORE:
             //validate request
             Validate::prime($xp->get());
             Validate::go('path')->not('blank');
             Validate::paint();
             //store new file
             $fileio->setPath($xp->get('path'));
             //send back file info
             return $xp->add('file', $fileio->store());
             break;
         default:
             throw new Exception('Invalid File IO action');
             break;
     }
 }
Beispiel #3
0
 public function read($offset = 0, $length = null, $crypt = null)
 {
     if (strpos($this->getMode(), 'w') === 0 || strpos($this->getMode(), 'a') === 0) {
         throw new Exception('Reading not supported in write/append only mode');
     }
     //set read length if null
     $readsize = min($this->getMaxReadLength(), $this->buffer_max);
     if (is_null($length)) {
         $length = $readsize;
     }
     //validate length format
     if (!is_numeric($length) || $length < 1) {
         throw new Exception('Read request must have a length');
     }
     //sanity check offset and length with known file size
     if ($offset > $this->getSize()) {
         return false;
     }
     //eof
     //clamp the length to what's left in the file
     if ($offset + $length > $this->getSize()) {
         $length = $this->getSize() - $offset;
     }
     //clamp length to max
     if ($length > $readsize) {
         $length = $readsize;
     }
     //calculate our buffer window
     $buf_start = $this->buffer_ptr === -1 ? 0 : $this->buffer_ptr;
     $buf_end = $buf_start + $this->getBufferSize();
     if ($offset < $buf_start || $offset + $length > $buf_end) {
         //we aren't in our buffered block, so fill the buffer with something useful
         //build request
         $url = $this->getURI();
         $data = $this->block_stream->encode();
         $rv = $this->call($url, array('action' => self::FILE_IO_READ, 'path' => $this->getPath(), 'offset' => $offset, 'length' => $readsize), $data);
         $rv = Stream::receive($data, $crypt)->decode();
         //first 40 bytes is the sha1
         $sha1 = substr($rv, 0, 40);
         //next 32 bytes is the md5
         $md5 = substr($rv, 40, 32);
         //strip the first 72 bytes to get the real paylod
         $rv = substr($rv, 72, strlen($rv));
         //verify sha1
         if (sha1($rv) !== $sha1) {
             throw new Exception('Read failed, payload hash mismatch (sha1)');
         }
         //verify the md5
         if (md5($rv) !== $md5) {
             throw new Exception('Read failed, payload hash mismatch (md5)');
         }
         //safe to buffer
         $this->setBuffer($offset, $rv);
     }
     //we should have the request data in the buffer now, deliver the request
     return $this->getBufferSlice($offset, $length);
 }
Beispiel #4
0
 public function call($uri, $cmd = array(), &$data = null, $flags = array())
 {
     $call_start = microtime(true);
     $url = $this->makeURL($uri);
     //inject auth params
     if (!is_callable(array($this->auth_handler, 'requestParams'))) {
         throw new Exception('Auth handler doesnt support requests');
     }
     $cmd = array_merge($cmd, call_user_func($this->auth_handler . '::requestParams'));
     //print some info
     $this->log->add('Setting up call to: ' . $url);
     $this->log->add('Command Params: ' . print_r($cmd, true));
     $this->log->add('Flags Present: ' . print_r($flags, true), Log::DEBUG);
     if (!is_null($data)) {
         $this->log->add('Data present (' . strlen($data) . '): ' . substr($data, 0, 50) . '...', Log::DEBUG);
     }
     //encode cmd params
     $request = $this->encode($cmd);
     $this->log->add('Request Encoded: ' . $request, Log::DEBUG);
     //start curl if needed
     if (!$this->ch) {
         $this->initCURL();
     }
     //set the url to hit
     curl_setopt($this->ch, CURLOPT_URL, $url);
     //add the payload to the stream
     $this->stream->setPayload($request);
     //setup curl post
     $post_query = http_build_query(array('request' => $this->stream->encode(), 'data' => $data));
     curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post_query);
     //if noexec is passed we simple pass the prepared curl handle back
     if (in_array(self::CALL_NOEXEC, $flags)) {
         return $this->ch;
     }
     //try the actual call
     $tries = 1;
     //TODO: tunables that need to be in the config
     $max_tries = 10;
     //the retry sleep gets multiplied by the number of tries
     //	thus the first call waits X ms and the last call waits X * $max_tries ms
     $retry_sleep = 300;
     //in ms
     //anything not defined here will trickle down and throw an exception
     $http_status_retry = array(5);
     $http_status_complete = array(2, 3);
     do {
         //execute the call
         $result = curl_exec($this->ch);
         if ($result === false) {
             throw new Exception('Call failed to ' . $url . ' ' . curl_error($this->ch));
         }
         //check the response status
         $http_status = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
         $http_status_class = floor($http_status / 100);
         if (in_array($http_status_class, $http_status_retry)) {
             $sleep_time = $retry_sleep * $tries;
             $this->log->add("Request failed with response code: " . $http_status . " retrying " . ($max_tries - $tries) . " more times waiting " . $sleep_time . "ms" . " until next try" . " req(" . $url . ")", Log::WARN);
             usleep($sleep_time * 1000);
             continue;
         }
         if (in_array($http_status_class, $http_status_complete)) {
             //exit the loop on success and continue
             break;
         }
         throw new Exception("Unrecognized HTTP RESPONSE CODE: " . $http_status);
     } while (++$tries < $max_tries);
     //separate channels
     parse_str($result, $response);
     unset($result);
     if (isset($response['data'])) {
         $data = $response['data'];
     }
     if (isset($response['debug']) && trim($response['debug']) != '') {
         debug_dump($response['debug']);
     }
     if (!isset($response['response'])) {
         throw new Exception('No response received with request: ' . print_r($response, true));
     }
     $response = $response['response'];
     //decode return payload
     $response = Stream::receive($response, $this->stream->getCrypt())->decode();
     $this->log->add('Response Raw (' . strlen($response) . '): ' . substr($response, 0, 50) . '...', Log::DEBUG);
     //decode the response
     $encoding = $this->decode($response);
     //log response
     if ($encoding != self::ENC_RAW) {
         // $response = array_shift($response);
         $this->log->add('Response received: ' . print_r($response, true), Log::DEBUG);
         //pass to error handler
         $this->errorHandler($response);
     }
     $this->log->add('Request took ' . number_format(microtime(true) - $call_start, 5) . ' seconds', Log::DEBUG);
     //if we got here there were no errors
     return $response;
 }