Hello,

Thanks for this module. I have used it successfully as a client for my custom Oauth implementation. However, there's some problem with the get method(DrupalOauthClient::get) when the HTTP method is set to POST. The problem is that at the endpoint, the server is not receiving the POST parameters. I did a simple test with drupal_http_request and it worked well.

A post at SO: http://stackoverflow.com/questions/4790413/php-curl-server-not-receiving... shows that this bit curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); shouldn't be there. I know you need it to send the Oauth params to the header, but is there an alternative way to achieve this without necessarily including the curl header options?

Thanks

Comments

drecute’s picture

I am subclassing DrupalOauthClient like this:


class PayOauthClient extends DrupalOauthClient {
  
  public function __construct($consumer, $request_token = NULL, $signature_method = NULL, $version = NULL) {
    parent::__construct($consumer, $request_token = NULL, $signature_method = NULL, $version = NULL);
  }
  public function get($path, $options = array()) {
    return parent::get($path, $options = array());
  }
}

// invoked within a function
try {
        $oauthclient = new PayOauthClient($consumer, $token_request);

        $path = UC_PAY_URL;
        $options = array(
          'token' => TRUE,
          'params' => $order,
          'realm' => NULL,
          'get' => FALSE
        );
        
        $result = $oauthclient->get($path, $options);
        
      } catch(Exception $e) {
        drupal_set_message($e->getMessage(), 'error');
        watchdog('uc_pay', t('@uid cannot continue with order process due to @error', array('@uid' => $order->uid, '@error' => $e->getMessage())), WATCHDOG_SEVERE);
        global $socket_closed;
        $socket_closed = TRUE;
      }
sun’s picture

Title: Oauth DrupalOauthClient get method not sending POST params » DrupalOauthClient::get() does not send POST parameters
Version: 6.x-3.0-beta4 » 7.x-3.x-dev
Priority: Normal » Major

The suggested solution is wrong. As also mentioned on SO, the cause is:

Content-Type had to be specifically set to application/x-www-form-urlencoded (not text/xml)

DrupalOAuthClient apparently sends the following, totally weird and invalid header:

    $headers = array(
      'Accept: application/x-www-form-urlencoded',
      $req->to_header($options['realm']),
    );

whereas the type specified in Accept belongs into Content-Type. Accept signifies what response formats the client is able to handle.

...and then it goes on and makes it even worse...

    if (!$options['get']) {
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, '');
    }

I'm not sure why the code is using all of that custom cURL code to execute requests instead of drupal_http_request(). Unless there's a really good reason for doing so, it's going to be way easier to replace that entire code.

drecute’s picture

Yes I agree that drupal_http_request is way easier, sun! I had to by-pass this bug in a subclass by writing a custom get function which uses drupal_http_request. here's what it looks like:

public function get($path, $options = array()) {
    $options += array(
        'token' => FALSE, // don't send a token along with the request
        'params' => array(),
        'realm' => NULL,
        'get' => FALSE,
      );

    if (empty($options['realm']) && !empty($this->consumer->configuration['authentication_realm'])) {
      $options['realm'] = $this->consumer->configuration['authentication_realm'];
    }

    $token_object = new stdClass();
    $token_object->key = variable_get('oauth_token', '');

    $token = $options['token'] ? $token_object : NULL; // If token is TRUE, variable_get it else return NULL
    $path = parent::getAbsolutePath($path);

    $req = OAuthRequest::from_consumer_and_token($this->consumer, $token,
      $options['get'] ? 'GET' : 'POST', $path, $options['params']);
    $req->sign_request($this->signatureMethod, $this->consumer, $token);

    $url = $req->get_normalized_http_url();
    $params = array();
    foreach ($req->get_parameters() as $param_key => $param_value) {
      if (substr($param_key, 0, 5) != 'oauth') {
        $params[$param_key] = $param_value;
      }
    }

    $headers = array(
      //'Accept: application/x-www-form-urlencoded',
      'Accept: application/json',
      $req->to_header($options['realm']),
    );
    $method = 'POST';
    // convert the data to json
    $data = json_encode($params);
    // log what is been sent
    watchdog('uc_pay', t('New Order! A user with @uid has just made a new order. Order data is @data', array('@uid' => $order->uid, '@data' => $data)));
    $result = drupal_http_request($url, $headers, $method, "fees=$data");

    if ($result->code != 200) {
      throw new Exception('Failed to fetch data from url "' . $path . '" (HTTP response code ' . $result->code . ' ' . $result->status_message . ')');
    }

    return $result;
  }