

[この質問](https://ja.stackoverflow.com/questions/55176/casablanca%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)と同じ内容ですが、状況が変わりましたので、再度質問させていただきます。

C++ REST SDK
を使用してTwitterのOAuth認証を行いたいのですが、Authorizationヘッダーを指定したときに例外が投げられます。try-
catchで例外を捕まえてみると、`WinHttpAddRequestHeaders: 87`とのコードが出ていました。

ネットで調べてみると、ヘッダーの文字数の上限(56)に達している？との[解説](https://forums.whirlpool.net.au/archive/2408802)がありました。  
しかしながら、[ここ](https://syncer.jp/Web/API/Twitter/REST_API/)のサイトにありますように、Authorizationヘッダーの内容は明らかに56文字を超えています。

この問題はどのように解決したらいいのでしょうか。  
以下にコード（.hppファイル）を載せますので、回答して頂けると幸いです。

あちらこちらでバラバラな質問をしてしまい申し訳ありません。

[code]

    #pragma once
    
    #include <sstream>
    #include <fstream>
    #include <vector>
    #include <locale>
    #include <winstring.h>
    #include <algorithm>
    #include <iomanip>
    #include <queue>
    #include <time.h>
    #include <cpprest/http_client.h>
    #include <openssl/hmac.h>
    #include <openssl/ssl.h>
    
    #pragma comment(lib,"libeay32.lib") 
    
    using namespace std;
    using namespace web;
    using namespace web::http;
    using namespace web::http::client;
    
    #define REST_POST_PATH "C:\\ProgramData\\System72\\CAIOS\\CAIOS\\REST_POST_RESPONSE.json"
    #define REST_GET_PATH "C:\\ProgramData\\System72\\CAIOS\\CAIOS\\REST_GET_RESPONSE.json"
    #define TWITTER_TWEET_URL "https://api.twitter.com/1.1/statuses/update.json"
    #define TWITTER_TIMELINE_URL "https://api.twitter.com/1.1/statuses/home_timeline.json"
    
    typedef enum {
        POST,
        GET
    } METHOD;
    
    enum CodePageID : unsigned int {
        ANSI = CP_ACP,  // ANSI
        OEM = CP_OEMCP, // OEM(依存)
        MAC = CP_MACCP, // MAC
        UTF7 = CP_UTF7, // UTF-7
        UTF8 = CP_UTF8  // UTF-8
    };
    
    struct Request {
        string url;
        string post;
        string header;
    };
    
    struct TwitterAPI_Keys {
        string Consumer_Key     = "";
        string Consumer_Sec     = "";
        string Accesstoken      = "";
        string Accesstoken_Aec  = "";
    };
    
    namespace CAIOS {
    
        namespace String {
    
            static string UTF8_to_SJIS(string message) {
                int n;
                wchar_t ucs2[1000];
                char utf8[1000];
                n = MultiByteToWideChar(CP_UTF8, 0, message.c_str(), message.size(), ucs2, 1000);
                n = WideCharToMultiByte(CP_ACP, 0, ucs2, n, utf8, 1000, 0, 0);
                return std::string(utf8, n);
            }
    
            static string SJIS_to_UTF8(std::string const& message)      {
                int n;
                wchar_t ucs2[1000];
                char utf8[1000];
                n = MultiByteToWideChar(CP_ACP, 0, message.c_str(), message.size(), ucs2, 1000);
                n = WideCharToMultiByte(CP_UTF8, 0, ucs2, n, utf8, 1000, 0, 0);
                return std::string(utf8, n);
            }
    
            // string から wstring 変換
            static wstring StringToWString(const string& refSrc, unsigned int codePage = CodePageID::ANSI) {
                vector<wchar_t> buffer(MultiByteToWideChar(codePage, 0, refSrc.c_str(), -1, nullptr, 0));
                MultiByteToWideChar(codePage, 0, refSrc.c_str(), -1, &buffer.front(), buffer.size());
                return wstring(buffer.begin(), buffer.end());
            }
    
            // wstring から string 変換
            static string WStringToString(const wstring& refSrc, unsigned int codePage = CodePageID::OEM) {
                vector<char> buffer(WideCharToMultiByte(codePage, 0, refSrc.c_str(), -1, nullptr, 0, nullptr, nullptr));
                WideCharToMultiByte(codePage, 0, refSrc.c_str(), -1, &buffer.front(), buffer.size(), nullptr, nullptr);
                return string(buffer.begin(), buffer.end());
            }
    
            static string EraseString(string str, string erase) {
                for (size_t c = str.find_first_of(erase); c != string::npos; c = c = str.find_first_of(erase)) {
                    str.erase(c, 1);
                }
                return str;
            }
        }
    
        namespace REST {
    
            static string GET(Request req) {
                try {
                    using namespace CAIOS::String;
    
                    http_client client(StringToWString(req.url));
                    http_request request(methods::GET);
    
                    cout << " -> HTTP request mode [GET]" << endl;
                    cout << " -> HTTP request to " << req.url << endl;
    
                    request.headers().add(L"Content-Type", L"application/x-www-form-urlencoded");
                    request.headers().add(L"Authorization", StringToWString(req.header));
    
                    http_response response = client.request(request).get(); //ここで例外
                    auto str = response.extract_string();
    
                    cout << " -> Server returned returned status code " << response.status_code() << '.' << endl;
                    cout << " -> Content length is " << response.headers().content_length() << " bytes.\n" << endl;
    
                    ofstream ofs(REST_GET_PATH);
                    ofs << WStringToString(str.get().c_str()) << endl;
                    ofs.close();
    
                    return WStringToString(str.get().c_str());
                }
                catch (exception & error) {
                    cout << error.what() << endl;
                    return "HTTP通信中に例外が発生しました　[GET]  ";
                }
            }
    
            static string POST(Request req) {
                try {
                    using namespace CAIOS::String;
    
                    http_client client(StringToWString(req.url));
    
                    http_request request(methods::POST);
    
                    cout << " -> HTTP request mode [POST]" << endl;
                    cout << " -> HTTP request to " << req.url << endl;
    
                    request.headers().add(L"Content-Type", L"application/x-www-form-urlencoded");
                    request.set_body(req.post);
    
                    http_response response = client.request(request).get();
                    auto str = response.extract_string();
    
                    cout << " -> Server returned returned status code " << response.status_code() << '.' << endl;
                    cout << " -> Content length is " << response.headers().content_length() << " bytes.\n" << endl;
    
                    ofstream ofs(REST_POST_PATH);
                    ofs << WStringToString(str.get().c_str()) << endl;
                    ofs.close();
    
                    return WStringToString(str.get().c_str());
                }
                catch (...) {
                    return "HTTP通信中に例外が発生しました　[POST]";
                }
            }
    
            static string URL_encode(string str) {
                const int NUM_BEGIN_UTF8 = 48;
                const int CAPITAL_BEGIN_UTF8 = 65;
                const int LOWER_BEGIN_UTF8 = 97;
    
                int charCode = -1;
                string encoded;
                stringstream out;
    
                for (int i = 0; str[i] != 0; i++) {
                    charCode = (int)(unsigned char)str[i];
    
                    //エンコードする必要の無い文字の判定
                    if ((NUM_BEGIN_UTF8 <= charCode && charCode <= NUM_BEGIN_UTF8 + 9)
                        || (CAPITAL_BEGIN_UTF8 <= charCode && charCode <= CAPITAL_BEGIN_UTF8 + 25)
                        || (LOWER_BEGIN_UTF8 <= charCode && charCode <= LOWER_BEGIN_UTF8 + 25)
                        || str[i] == '.' || str[i] == '_' || str[i] == '-' || str[i] == '~'){
                        out << str[i];
                    }
                    else {
                        out << '%' << hex << uppercase << charCode;
                    }
                }
                encoded = out.str();
                return encoded;
            }
        }
    
        namespace Twitter {
            namespace OAuth {
                static string CreateAuthorization(vector<string>const Option, int Start1, vector<string>const OAuth, int Start2) {
                    string Authorization = "OAuth ";
    
                    for (int t = Start1; t < Option.size(); t++) {
                        Authorization += Option[t] + ",";
                    }
                    for (int t = Start2; t < OAuth.size(); t++) {
                        Authorization += OAuth[t] + ",";
                    }
    
                    Authorization.pop_back();
                    return Authorization;
                }
    
                static string CreateData(vector<string>const OAuth, METHOD method, int Start) {
                    string query;
    
                    if (method == POST) {
                        for (int t = Start; t < OAuth.size(); t++) {
                            if (t != Start)query += "&";
                            query += OAuth[t];
                        }
                    }
                    else if (method == GET) {
                        for (int t = Start; t < OAuth.size(); t++) {
                            query += OAuth[t];
                            if (t == Start)query += "?";
                            else query += "&";
                        }
                        query.pop_back();
                    }
    
                    return query;
                }
    
                static int split_url(const string url, vector<string>* Option, vector<string>* OAuth) {
                    int num = url.find_first_of('?');
                    OAuth->push_back(url.substr(0, num));
                    OAuth->push_back(url.substr(num + 1));
                    Option->push_back(url.substr(0, num));
                    Option->push_back(url.substr(num + 1));
                    return 0;
                }
    
                static string sha1(const string Key, const string Data) {
                    char* key = (char*)Key.c_str();
                    char* data = (char*)Data.c_str();
                    unsigned char res[SHA_DIGEST_LENGTH + 1];
                    size_t reslen;
    
                    HMAC(EVP_sha1(), key, strlen(key), reinterpret_cast<const unsigned char*>(data), strlen(data), res, &reslen);
    
                    return string(reinterpret_cast<char*>(res), reslen);
                }
    
                static int encode_base64(char* bufin, int len, char* bufout){
                    static unsigned char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
                    unsigned char* pin = (unsigned char*)bufin;
                    unsigned char* pout = (unsigned char*)bufout;
    
                    for (int i = 0; i < len - 2; i += 3){
                        *pout++ = base64[pin[0] >> 2];
                        *pout++ = base64[0x3F & ((pin[0] << 4) | (pin[1] >> 4))];
                        *pout++ = base64[0x3F & ((pin[1] << 2) | (pin[2] >> 6))];
                        *pout++ = base64[0x3F & pin[2]];
                        pin += 3;
                    }
                    if (len % 3 == 1){
                        *pout++ = base64[pin[0] >> 2];
                        *pout++ = base64[0x3F & (pin[0] << 4)];
                        *pout++ = '=';
                        *pout++ = '=';
                    }
                    else if (len % 3 == 2){
                        *pout++ = base64[pin[0] >> 2];
                        *pout++ = base64[0x3F & ((pin[0] << 4) | (pin[1] >> 4))];
                        *pout++ = base64[0x3F & (pin[1] << 2)];
                        *pout++ = '=';
                    }
                    *pout = '\0';
                    return pout - (unsigned char*)bufout;
                }
    
                static string CreateSignature(string ConsumerSecret, string AccessSecret, vector<string>const& OAuth, METHOD method, int Start = 1) {
                    string str, key, data, methods;
                    char out[256];
    
                    if (method == POST)methods = "POST";
                    else methods = "GET";
    
                    key = CAIOS::REST::URL_encode(ConsumerSecret) + "&" + CAIOS::REST::URL_encode(AccessSecret);
    
                    data = methods + "&" + CAIOS::REST::URL_encode(OAuth[0]) + "&" + CAIOS::REST::URL_encode(CreateData(OAuth, method, Start));
    
                    str = sha1(key, data);
    
                    CAIOS::Twitter::OAuth::encode_base64((char*)str.c_str(), str.size(), out);
    
                    return CAIOS::REST::URL_encode(out);
                }
    
                static int IntOAuthParams(vector<string>* OAuth, METHOD method) {
                    TwitterAPI_Keys key;
    
                    auto CreateNonce = []() {
                        static const char* chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
                        const unsigned int max = 26 + 26 + 10 + 1;
                        char tmp[50];
                        srand((unsigned int)time(0));
                        int len = 15 + rand() % 16;
                        for (int i = 0; i < len; i++) {
                            tmp[i] = chars[rand() % max];
                        }
                        return std::string(tmp, len);
                    };
    
                    string oauth_nonce = "oauth_nonce";
                    oauth_nonce += "=";
                    oauth_nonce += CreateNonce();
                    OAuth->push_back(oauth_nonce);
    
                    string oauth_timestamp = "oauth_timestamp";
                    oauth_timestamp += "=";
                    oauth_timestamp += to_string((int)time(nullptr));
                    OAuth->push_back(oauth_timestamp);
    
                    string oauth_token = "oauth_token";
                    oauth_token += "=";
                    oauth_token += key.Accesstoken;
                    OAuth->push_back(oauth_token);
    
                    string oauth_consumer_key = "oauth_consumer_key";
                    oauth_consumer_key += "=";
                    oauth_consumer_key += key.Consumer_Key;
                    OAuth->push_back(oauth_consumer_key);
    
                    string oauth_signature_method = "oauth_signature_method";
                    oauth_signature_method += "=";
                    oauth_signature_method += "HMAC-SHA1";
                    OAuth->push_back(oauth_signature_method);
    
                    string oauth_version = "oauth_version";
                    oauth_version += "=";
                    oauth_version += "1.0";
                    OAuth->push_back(oauth_version);
    
                    sort(OAuth->begin() + 1, OAuth->end());
    
                    string oauth_signature = "oauth_signature";
                    oauth_signature += "=";
                    oauth_signature += CreateSignature(key.Consumer_Sec, key.Accesstoken_Aec, *OAuth, method);
                    OAuth->push_back(oauth_signature);
    
                    return 0;
                }
    
                static Request OAuthAuthentication(string url, METHOD method) {
                    vector<string> OAuth;
                    vector<string> Option;
    
                    CAIOS::Twitter::OAuth::split_url(url, &Option, &OAuth);
    
                    CAIOS::Twitter::OAuth::IntOAuthParams(&OAuth, method);
    
                    Request req;
    
                    if (method == POST) {
                        req.url = OAuth[0];
                        req.post = CAIOS::Twitter::OAuth::CreateData(OAuth, method, 1);
                        req.header = "";
                    }
                    else if (method == GET) {
                        req.url = CAIOS::Twitter::OAuth::CreateData(Option, method, 0);
                        req.post = "";
                        req.header = CreateAuthorization(Option, 1, OAuth, 2);
                    }
    
                    return req;
                }
            }
    
            static string Tweet(string message) {
                message = CAIOS::String::SJIS_to_UTF8(message);
    
                string url = TWITTER_TWEET_URL;
                url += "?status=" + CAIOS::REST::URL_encode(message);
    
                Request req = OAuth::OAuthAuthentication(url, POST);
                return CAIOS::REST::POST(req);
            }
    
            static string TimeLine(int num) {
                string url = TWITTER_TIMELINE_URL;
                url += "?count=" + to_string(num);
    
                Request req = OAuth::OAuthAuthentication(url, GET);
                return CAIOS::REST::GET(req);
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2019-05-23T09:36:18.127
55197
2019-05-24T05:55:51.300
question
c++ twitter rest
C++ REST SDKでAuthorizationヘッダが指定できない


リクエストヘッダーの文字数の上限が56なんてことはありえません。そんなに短ければ、一般的によく使用するようなリクエストヘッダーでもすぐに制限に引っかかってしまいます。

> From my experience, a username with 56 characters is still OK. You can check
> it at <https://technet.microsoft.com/en-us/library/cc783323.aspx> and the
> permitted length of username is 256 characters

前半の「56」は「256」のtypoでしょう。後半で「the permitted length of username is 256
characters」と言っているので。ただ、この引用しているページもActive
Directoryのユーザー名の制限についての解説ページなので、本件とは無関係でしょうね。

C++の文法はよく分かりませんが、少なくともこの行は間違っていますよね。

[code]

    request.headers().add(L"Authorization", StringToWString(req.header));
    
[/code]

別のリクエストのヘッダー全体を文字列化したものを、`Authorization`ヘッダーにセットしているように見えます。

APIの仕様をよく読んで、適切なリクエストを送信するように修正して下さい。


CC BY-SA 4.0
2019-05-24T00:58:23.403
55210
2019-05-24T05:55:51.300
2019-05-24T05:55:51.300
21092
21092
55197
answer