/** * Fetches the content and returns it as-is using the headers as returned * by the remote host. * * @param string $url the url to retrieve */ public function fetch($url) { // TODO: Check to see if we can just use MakeRequestOptions::fromCurrentRequest $st = isset($_GET['st']) ? $_GET['st'] : (isset($_POST['st']) ? $_POST['st'] : false); $body = isset($_GET['postData']) ? $_GET['postData'] : (isset($_POST['postData']) ? $_POST['postData'] : false); $authz = isset($_GET['authz']) ? $_GET['authz'] : (isset($_POST['authz']) ? $_POST['authz'] : null); $headers = isset($_GET['headers']) ? $_GET['headers'] : (isset($_POST['headers']) ? $_POST['headers'] : null); $params = new MakeRequestOptions($url); $params->setSecurityTokenString($st)->setAuthz($authz)->setRequestBody($body)->setHttpMethod('GET')->setFormEncodedRequestHeaders($headers)->setNoCache($this->context->getIgnoreCache()); $result = $this->makeRequest->fetch($this->context, $params); $httpCode = (int) $result->getHttpCode(); $cleanedResponseHeaders = $this->makeRequest->cleanResponseHeaders($result->getResponseHeaders()); $isShockwaveFlash = false; foreach ($cleanedResponseHeaders as $key => $val) { header("{$key}: {$val}", true); if (strtoupper($key) == 'CONTENT-TYPE' && strtolower($val) == 'application/x-shockwave-flash') { // We're skipping the content disposition header for flash due to an issue with Flash player 10 // This does make some sites a higher value phishing target, but this can be mitigated by // additional referer checks. $isShockwaveFlash = true; } } if (!$isShockwaveFlash && !Config::get('debug')) { header('Content-Disposition: attachment;filename=p.txt'); } $lastModified = $result->getResponseHeader('Last-Modified') != null ? $result->getResponseHeader('Last-Modified') : gmdate('D, d M Y H:i:s', $result->getCreated()) . ' GMT'; $notModified = false; if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $lastModified && !isset($_SERVER['HTTP_IF_NONE_MATCH'])) { $if_modified_since = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); // Use the request's Last-Modified, otherwise fall back on our internal time keeping (the time the request was created) $lastModified = strtotime($lastModified); if ($lastModified <= $if_modified_since) { $notModified = true; } } if ($httpCode == 200) { // only set caching headers if the result was 'OK' $this->setCachingHeaders($lastModified); // was the &gadget=<gadget url> specified in the request? if so parse it and check the rewrite settings if (isset($_GET['gadget'])) { $this->rewriteContent($_GET['gadget'], $result); } } // If the cached file time is within the refreshInterval params value, return not-modified if ($notModified) { header('HTTP/1.0 304 Not Modified', true); header('Content-Length: 0', true); } else { header("HTTP/1.1 {$httpCode} " . $result->getHttpCodeMsg()); // then echo the content echo $result->getResponseContent(); } }
public function doGet() { try { $this->noHeaders = true; $context = new GadgetContext('GADGET'); $makeRequestParams = MakeRequestOptions::fromCurrentRequest(); $makeRequestHandler = new MakeRequestHandler($context); $makeRequestHandler->fetchJson($makeRequestParams); } catch (MakeRequestParameterException $e) { // Something was misconfigured in the request header("HTTP/1.0 400 Bad Request", true); echo "<html><body><h1>400 - Bad request</h1><p>" . $e->getMessage() . "</body></html>"; } catch (Exception $e) { // catch all exceptions and give a 500 server error header("HTTP/1.0 500 Internal Server Error"); echo "<html><body><h1>Internal server error</h1><p>" . $e->getMessage() . "</p></body></html>"; } }
/** * Processes an RPC request for http data. * * @param RequestItem $requestItem The request parameters. * @return array An array of content, status code, and headers from the * response. The expected structure is undocumented in the spec, sadly. * TODO: Filter some/most headers from the response (waste of bandwidth). */ public function handleItem(RequestItem $requestItem) { try { // We should only get RPC requests at this point. There's a class cast // here from RequestItem->RpcRequestItem, but PHP doesn't seem to // complain. $options = MakeRequestOptions::fromRpcRequestItem($requestItem); $makeRequest = new MakeRequest(); $context = new GadgetContext('GADGET'); $response = $makeRequest->fetch($context, $options); $result = array('content' => $response->getResponseContent(), 'status' => $response->getHttpCode(), 'headers' => $response->getResponseHeaders()); } catch (SocialSpiException $e) { $result = new ResponseItem($e->getCode(), $e->getMessage()); } catch (Exception $e) { $result = new ResponseItem(ResponseError::$INTERNAL_ERROR, "Internal error: " . $e->getMessage()); } return $result; }
/** * Processes an RPC request for http data. * * @param RequestItem $requestItem The request parameters. * @return array An array of content, status code, and headers from the * response. The expected structure is undocumented in the spec, sadly. * TODO: Filter some/most headers from the response (waste of bandwidth). */ public function handleItem(RequestItem $requestItem) { try { // We should only get RPC requests at this point. There's a class cast // here from RequestItem->RpcRequestItem, but PHP doesn't seem to // complain. $options = MakeRequestOptions::fromRpcRequestItem($requestItem); $makeRequestClass = Config::get('makerequest_class'); $makeRequest = new $makeRequestClass(); $contextClass = Config::get('gadget_context_class'); $context = new $contextClass('GADGET'); $response = $makeRequest->fetch($context, $options); // try to decode json object here since in order // to not break gadgets.io.makeRequest functionality // $response->getResponseContent() has to return a string $content = json_decode($response->getResponseContent(), true); $result = array('content' => $content ? $content : $response->getResponseContent(), 'status' => $response->getHttpCode(), 'headers' => $response->getResponseHeaders()); } catch (SocialSpiException $e) { $result = new ResponseItem($e->getCode(), $e->getMessage()); } catch (Exception $e) { $result = new ResponseItem(ResponseError::$INTERNAL_ERROR, "Internal error: " . $e->getMessage()); } return $result; }
/** * Builds a MakeRequestOptions object from a RequestItem instance. This is * a helper for dealing with Handler services which need to call MakeRequest. * The parameter names were taken from the osapi.http spec documents, although * several parameters not in the spec are also supported to allow full * functionality. * * @param RpcRequestItem $request The RpcRequestItem to parse. The reason * RpcRequestItem is needed is because of the way getService() and * getMethod() are overloaded in the RequestItem subclasses. This * function needs a reliable way to get the http method. * @return MakeRequestOptions An object initialized from the current request. * @throws MakeRequestParameterException If any of the parameters were * invalid. */ public static function fromRpcRequestItem(RpcRequestItem $request) { $href = $request->getParameter('href'); if (!isset($href)) { $href = $request->getParameter('url'); } $options = new MakeRequestOptions($href); $options->setHttpMethod($request->getMethod())->setRequestBody($request->getParameter('body'))->setRequestHeaders($request->getParameter('headers', array()))->setResponseFormat($request->getParameter('format'))->setAuthz($request->getParameter('authz'))->setSignViewer($request->getParameter('sign_viewer'))->setSignOwner($request->getParameter('sign_owner'))->setNumEntries($request->getParameter('numEntries'))->setGetSummaries($request->getParameter('getSummaries'))->setRefreshInterval($request->getParameter('refreshInterval'))->setNoCache($request->getParameter('nocache'))->setOAuthServiceName($request->getParameter('oauth_service_name'))->setOAuthTokenName($request->getParameter('oauth_token_name'))->setOAuthRequestToken($request->getParameter('oauth_request_token'))->setOAuthRequestTokenSecret($request->getParameter('oauth_request_token_secret'))->setOAuthUseToken($request->getParameter('oauth_use_token'))->setOAuthReceivedCallback($request->getParameter('oauth_received_callback'))->setOAuthClientState($request->getParameter('oauth_state'))->setSecurityTokenString($request->getToken()->toSerialForm()); return $options; }
/** * Builds a request to retrieve the actual content. * * @param GadgetContext $context The rendering context. * @param MakeRequestOptions $params Options for crafting the request. * @param SecurityTokenDecoder $signer A signer needed for signed requests. * @return RemoteContentRequest An initialized request object. */ public function buildRequest(GadgetContext $context, MakeRequestOptions $params, SecurityTokenDecoder $signer = null) { // Check the protocol requested - curl doesn't really support file:// // requests but the 'error' should be handled properly $protocolSplit = explode('://', $params->getHref(), 2); if (count($protocolSplit) < 2) { throw new Exception("Invalid protocol specified"); } $protocol = strtoupper($protocolSplit[0]); if ($protocol != "HTTP" && $protocol != "HTTPS") { throw new Exception("Invalid protocol specified in url: " . htmlentities($protocol)); } $method = $params->getHttpMethod(); if ($method == 'POST' || $method == 'PUT') { // even if postData is an empty string, it will still post // (since RemoteContentRquest checks if its false) // so the request to POST is still honored $request = new RemoteContentRequest($params->getHref(), null, $params->getRequestBody()); } else { if ($method == 'DELETE' || $method == 'GET' || $method == 'HEAD') { $request = new RemoteContentRequest($params->getHref()); } else { throw new Exception("Invalid HTTP method."); } } $request->setMethod($method); if ($signer) { switch ($params->getAuthz()) { case 'SIGNED': $request->setAuthType(RemoteContentRequest::$AUTH_SIGNED); break; case 'OAUTH': $request->setAuthType(RemoteContentRequest::$AUTH_OAUTH); $request->setOAuthRequestParams($params->getOAuthRequestParameters()); break; } $st = $params->getSecurityTokenString(); if ($st === false) { throw new Exception("A security token is required for signed requests"); } $token = $context->validateToken($st, $signer); $request->setToken($token); } // Strip invalid request headers. This limits the utility of the // MakeRequest class a little bit, but ensures that none of the invalid // headers are present in any request going through this class. $headers = $params->getRequestHeadersArray(); if ($headers !== false) { $headers = $this->stripInvalidArrayKeys($headers, MakeRequest::$BAD_REQUEST_HEADERS); $params->setRequestHeaders($headers); } // The request expects headers to be stored as a normal header text blob. // ex: Content-Type: application/atom+xml // Accept-Language: en-us $formattedHeaders = $params->getFormattedRequestHeaders(); if ($formattedHeaders !== false) { $request->setHeaders($formattedHeaders); } return $request; }
public function testResponseHeaders() { $params = new MakeRequestOptions('http://www.example.com'); $params->setNoCache(true); $headers = array('Content-Type' => 'text/plain'); $this->response->setResponseHeaders($headers); $this->fetcher->enqueueResponse($this->response); $result = $this->makeRequest->fetch($this->context, $params); $response_headers = $result->getResponseHeaders(); $this->assertArrayHasKey('Content-Type', $response_headers); $this->assertEquals('text/plain', $response_headers['Content-Type']); }