2013-06-12 3 views
0

Я пытаюсь разработать настольное приложение, которое использует dropbox. Я использую C++, libcurl (для запросов) liboauthcpp (для аутентификации) и Rest API (из Dropbox).error: Invalid Signature при загрузке файлов на Dropbox

Поскольку я успешно прошел аутентификацию и еще несколько операций (список и файл загрузки), я не могу загрузить файл. Я получаю следующее сообщение об ошибке: { "Ошибка": "Invalid подпись"}

Вот мой код:

m_upload_url = "https://api-content.dropbox.com/1/files/sandbox/"; 

     OAuth::Consumer consumer(m_consumer_key, m_consumer_secret); 
     OAuth::KeyValuePairs access_token_resp_data = OAuth::ParseKeyValuePairs(m_access_token_Response); 
     OAuth::Token access_token = OAuth::Token::extract(access_token_resp_data); 
     OAuth::Client oauth = OAuth::Client(&consumer, &access_token); 
     string oAuthQueryString = oauth.getURLQueryString(OAuth::Http::Post, m_upload_url); 

     string upload_Request = (string(m_upload_url) + string("?") + oAuthQueryString); 

     CURL *curl; 
     CURLcode res; 

     struct curl_httppost *formpost=NULL; 
     struct curl_httppost *lastptr=NULL; 
     struct curl_slist *headerlist=NULL; 
     static const char buf[] = "Expect:"; 

     curl_global_init(CURL_GLOBAL_ALL); 

     /* Fill in the file upload field */ 
     curl_formadd(&formpost, 
         &lastptr, 
         CURLFORM_COPYNAME, "file", 
         CURLFORM_FILE, "C:/Users/Desktop/textfile.txt", 
         CURLFORM_END); 

     /* Fill in the filename field */ 
     curl_formadd(&formpost, 
         &lastptr, 
         CURLFORM_COPYNAME, "name", 
         CURLFORM_COPYCONTENTS, "textfile", 
         CURLFORM_END); 


     /* Fill in the submit field too, even if this is rarely needed */ 
     curl_formadd(&formpost, 
         &lastptr, 
         CURLFORM_COPYNAME, "submit", 
         CURLFORM_COPYCONTENTS, "send", 
         CURLFORM_END); 

     curl = curl_easy_init(); 
     /* initalize custom header list (stating that Expect: 100-continue is not 
      wanted */ 
     headerlist = curl_slist_append(headerlist, buf); 
     if(curl) { 
      /* what URL that receives this POST */ 
      curl_easy_setopt(curl, CURLOPT_URL, upload_Request.c_str()); 
      /* only disable 100-continue header if explicitly requested */ 
      curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1L); 
      curl_easy_setopt(curl, CURLOPT_POST, 1L); 
      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); 
      curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); 
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction); 
      curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 

      /* Perform the request, res will get the return code */ 
      res = curl_easy_perform(curl); 
      string response = string(gData); 

      qDebug() << QString::fromStdString(response); 

      /* Check for errors */ 
      if(res != CURLE_OK) 
      qDebug() << "curl_easy_perform() failed: %s\n" << curl_easy_strerror(res); 

      /* always cleanup */ 
      curl_easy_cleanup(curl); 

      /* then cleanup the formpost chain */ 
      curl_formfree(formpost); 
      /* free slist */ 
      curl_slist_free_all (headerlist); 
     } 

и вот writeFunction:

char gData[1024*1024]; 
unsigned int gDataLen = 0; 

size_t writeFunction(char *ptr, size_t size, size_t nmemb) 
{ 
    memcpy(&(gData[gDataLen]), ptr, (size * nmemb)); 
    gDataLen += (size * nmemb); 
    gData[ gDataLen ] = '\0'; 
    return (size * nmemb); 
} 

Любые идеи, пожалуйста?

EDIT:

Вот запрос, что настоящий код производит: https://api-content.dropbox.com/1/files/sandbox/?oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_nonce=13xxxxxx83cf&oauth_signature=xxxxxx%xxxxxxxxxxxxxxxxxx%xxxxx%xx&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1371107283&oauth_token=xxxxxxxxxxxxxxx&oauth_version=1.0

и запрос, который я Продус с открытым текстом методом: https://api-content.dropbox.com/1/files/sandbox/?oauth_version=1.0&oauth_signature_method=PLAINTEXT&oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_token=xxxxxxxxxxxxxxx&oauth_signature=xxxxxxxxxxxxxxx&xxxxxxxxxxxxxxx

Response, что O получить в обоих случаях : {"error": "Invalid signature."}

ответ

1

Какой метод подписи OAuth вы используете? Если это ничего, кроме открытого текста, то я считаю, что проблема заключается в том, что вы не передаете тело HTTP-запроса getURLQueryString. Тело должно быть частью строки, которая подписана. Это объясняет, почему вы смогли получить несколько операций GET; эти просьбы не имеют тела.

Замечание: похоже, вы используете POST-форму для загрузки файла, что, as the docs say значительно сложнее, чем PUT. Я думаю, что ваша жизнь будет лучше, если вы переключитесь. :-) Например, я думаю, что поле submit, которое вы добавляете, вероятно, приведет к тому, что вызов не будет работать.

EDIT: Вот полный рабочий пример с использованием созданной вручную текстовой информации. Заполните ключ приложения, приложения секрет, маркер и секрет маркера, и убедитесь, что файл с именем «hello.txt» для этой работы:

#include <stdio.h> 
#include <curl/curl.h> 
#include <iostream> 
#include <fstream> 

using namespace std; 

size_t read_data(void *ptr, size_t size, size_t nmeb, void *stream) 
{ 
    return fread(ptr,size,nmeb,(FILE*)stream); 
} 

int main(void) 
{ 
    CURL *curl; 
    CURLcode res; 

    FILE * rfp = fopen("hello.txt", "r"); 

    string appkey = "<APP KEY>"; 
    string appsecret = "<APP SECRET>"; 
    string token = "<ACCESS TOKEN>"; 
    string token_secret = "<ACCESS TOKEN SECRET>"; 

    curl = curl_easy_init(); 
    if(curl) { 
    curl_easy_setopt(curl, CURLOPT_URL, "https://api-content.dropbox.com/1/files_put/sandbox/hello.txt"); 

    struct curl_slist *headers = NULL; 
    string header = "Authorization: OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\"" + appkey + "\", oauth_token=\"" + token + "\", oauth_signature=\"" + appsecret + "&" + token_secret + "\""; 
    headers = curl_slist_append(headers, header.c_str()); 
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 

    curl_easy_setopt(curl, CURLOPT_PUT, 1L); 
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data); 
    curl_easy_setopt(curl, CURLOPT_READDATA, rfp); 

    res = curl_easy_perform(curl); 

    curl_slist_free_all(headers); 
    if(res != CURLE_OK) 
     fprintf(stderr, "curl_easy_perform() failed: %s\n", 
       curl_easy_strerror(res)); 

    curl_easy_cleanup(curl); 
    } 

    fclose(rfp); 

    return 0; 
} 
+0

Я думаю, что я передаю тело HTTP-запроса getURLQueryString, написав: – michalis

+0

, пожалуйста, проверьте мое редактирование – michalis

+0

Я также попробовал «PUT», но я все равно получаю ту же ошибку. – michalis

0

Кто-нибудь использовал liboauthcpp? Я подозреваю, что моя ошибка в том, как я использую getURLQueryString. Я передаю URL-адрес этой функции, но я не уверен, должен ли я передавать данные. И, к сожалению, для этой библиотеки нет документации.

+0

Это то, на что мой ответ указал. Ваш код не передает тело HTTP-запроса 'getURLQueryString'. – smarx

Смежные вопросы