Changeset 2444 for box/trunk/test


Ignore:
Timestamp:
07/01/2009 17:31:04 (3 years ago)
Author:
chris
Message:

Initial implementations of S3Client class.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • box/trunk/test/httpserver/testhttpserver.cpp

    r2442 r2444  
    1010#include "Box.h" 
    1111 
    12 #include <stdio.h> 
    13 #include <string.h> 
     12#include <cstdio> 
     13#include <cstring> 
     14#include <ctime> 
    1415 
    1516#include <openssl/hmac.h> 
    1617 
     18#include "autogen_HTTPException.h" 
    1719#include "HTTPRequest.h" 
    1820#include "HTTPResponse.h" 
     
    199201                unsigned char digest_buffer[EVP_MAX_MD_SIZE]; 
    200202                unsigned int digest_size = sizeof(digest_buffer); 
    201                 unsigned char* mac = HMAC(EVP_sha1(), 
     203                /* unsigned char* mac = */ HMAC(EVP_sha1(), 
    202204                        secret_key.c_str(), secret_key.size(), 
    203205                        (const unsigned char*)data_string.c_str(), 
     
    325327} 
    326328 
     329class S3Client 
     330{ 
     331        public: 
     332        S3Client(S3Simulator* pSimulator, const std::string& rHostName, 
     333                const std::string& rAccessKey, const std::string& rSecretKey) 
     334        : mpSimulator(pSimulator), 
     335          mHostName(rHostName), 
     336          mAccessKey(rAccessKey), 
     337          mSecretKey(rSecretKey) 
     338        { } 
     339         
     340        S3Client(std::string HostName, int Port, const std::string& rAccessKey, 
     341                const std::string& rSecretKey) 
     342        : mpSimulator(NULL), 
     343          mHostName(HostName), 
     344          mPort(Port), 
     345          mAccessKey(rAccessKey), 
     346          mSecretKey(rSecretKey) 
     347        { } 
     348                 
     349        HTTPResponse GetObject(const std::string& rObjectURI); 
     350 
     351        private: 
     352        S3Simulator* mpSimulator; 
     353        std::string mHostName; 
     354        int mPort; 
     355        std::auto_ptr<SocketStream> mapClientSocket; 
     356        std::string mAccessKey, mSecretKey; 
     357 
     358        HTTPResponse FinishAndSendRequest(HTTPRequest::Method Method, 
     359                const std::string& rRequestURI, 
     360                IOStream* pStreamToSend = NULL, 
     361                const char* pStreamContentType = NULL); 
     362        HTTPResponse SendRequest(HTTPRequest& rRequest, 
     363                IOStream* pStreamToSend = NULL, 
     364                const char* pStreamContentType = NULL); 
     365}; 
     366 
     367HTTPResponse S3Client::GetObject(const std::string& rObjectURI) 
     368{ 
     369        return FinishAndSendRequest(HTTPRequest::Method_GET, rObjectURI); 
     370} 
     371 
     372HTTPResponse S3Client::FinishAndSendRequest(HTTPRequest::Method Method, 
     373        const std::string& rRequestURI, IOStream* pStreamToSend, 
     374        const char* pStreamContentType) 
     375{ 
     376        HTTPRequest request(Method, rRequestURI); 
     377        request.SetHostName(mHostName); 
     378         
     379        std::ostringstream date; 
     380        time_t tt = time(NULL); 
     381        struct tm *tp = gmtime(&tt); 
     382        if (!tp) 
     383        { 
     384                BOX_ERROR("Failed to get current time"); 
     385                THROW_EXCEPTION(HTTPException, Internal); 
     386        } 
     387        const char *dow[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; 
     388        date << dow[tp->tm_wday] << ", "; 
     389        const char *month[] = {"Jan","Feb","Mar","Apr","May","Jun", 
     390                "Jul","Aug","Sep","Oct","Nov","Dec"}; 
     391        date << std::internal << std::setfill('0') << 
     392                std::setw(2) << tp->tm_mday << " " << 
     393                month[tp->tm_mon] << " " << 
     394                (tp->tm_year + 1900) << " "; 
     395        date << std::setw(2) << tp->tm_hour << ":" << 
     396                std::setw(2) << tp->tm_min  << ":" << 
     397                std::setw(2) << tp->tm_sec  << " GMT"; 
     398        request.AddHeader("Date", date.str()); 
     399 
     400        if (pStreamContentType) 
     401        { 
     402                request.AddHeader("Content-Type", pStreamContentType); 
     403        } 
     404         
     405        std::string s3suffix = ".s3.amazonaws.com"; 
     406        std::string bucket; 
     407        if (mHostName.size() > s3suffix.size()) 
     408        { 
     409                std::string suffix = mHostName.substr(mHostName.size() - 
     410                        s3suffix.size(), s3suffix.size()); 
     411                if (suffix == s3suffix) 
     412                { 
     413                        bucket = mHostName.substr(0, mHostName.size() - 
     414                                s3suffix.size()); 
     415                } 
     416        } 
     417         
     418        std::ostringstream data; 
     419        data << request.GetVerb() << "\n"; 
     420        data << "\n"; /* Content-MD5 */ 
     421        data << request.GetContentType() << "\n"; 
     422        data << date.str() << "\n"; 
     423                 
     424        if (! bucket.empty()) 
     425        { 
     426                data << "/" << bucket; 
     427        } 
     428         
     429        data << request.GetRequestURI(); 
     430        std::string data_string = data.str(); 
     431 
     432        unsigned char digest_buffer[EVP_MAX_MD_SIZE]; 
     433        unsigned int digest_size = sizeof(digest_buffer); 
     434        /* unsigned char* mac = */ HMAC(EVP_sha1(), 
     435                mSecretKey.c_str(), mSecretKey.size(), 
     436                (const unsigned char*)data_string.c_str(), 
     437                data_string.size(), digest_buffer, &digest_size); 
     438        std::string digest((const char *)digest_buffer, digest_size); 
     439         
     440        base64::encoder encoder; 
     441        std::string auth_code = "AWS " + mAccessKey + ":" + 
     442                encoder.encode(digest); 
     443 
     444        if (auth_code[auth_code.size() - 1] == '\n') 
     445        { 
     446                auth_code = auth_code.substr(0, auth_code.size() - 1); 
     447        } 
     448 
     449        request.AddHeader("Authorization", auth_code); 
     450         
     451        if (mpSimulator) 
     452        { 
     453                if (pStreamToSend) 
     454                { 
     455                        pStreamToSend->CopyStreamTo(request); 
     456                } 
     457 
     458                request.SetForReading(); 
     459                CollectInBufferStream response_buffer; 
     460                HTTPResponse response(&response_buffer); 
     461         
     462                mpSimulator->Handle(request, response); 
     463                return response; 
     464        } 
     465        else 
     466        { 
     467                try 
     468                { 
     469                        if (!mapClientSocket.get()) 
     470                        { 
     471                                mapClientSocket.reset(new SocketStream()); 
     472                                mapClientSocket->Open(Socket::TypeINET, 
     473                                        mHostName, mPort); 
     474                        } 
     475                        return SendRequest(request, pStreamToSend, 
     476                                pStreamContentType); 
     477                } 
     478                catch (ConnectionException &ce) 
     479                { 
     480                        if (ce.GetType() == ConnectionException::SocketWriteError) 
     481                        { 
     482                                // server may have disconnected us, 
     483                                // try to reconnect, just once 
     484                                mapClientSocket->Open(Socket::TypeINET, 
     485                                        mHostName, mPort); 
     486                                return SendRequest(request, pStreamToSend, 
     487                                        pStreamContentType); 
     488                        } 
     489                        else 
     490                        { 
     491                                throw; 
     492                        } 
     493                } 
     494        } 
     495} 
     496 
     497HTTPResponse S3Client::SendRequest(HTTPRequest& rRequest, 
     498        IOStream* pStreamToSend, const char* pStreamContentType) 
     499{                
     500        HTTPResponse response; 
     501         
     502        if (pStreamToSend) 
     503        { 
     504                rRequest.SendWithStream(*mapClientSocket, 
     505                        30000 /* milliseconds */, 
     506                        pStreamToSend, response); 
     507        } 
     508        else 
     509        { 
     510                rRequest.Send(*mapClientSocket, 30000 /* milliseconds */); 
     511                response.Receive(*mapClientSocket, 30000 /* milliseconds */); 
     512        } 
     513                 
     514        return response; 
     515}        
     516 
    327517int test(int argc, const char *argv[]) 
    328518{ 
     
    437627        TestRemoteProcessMemLeaks("generic-httpserver.memleaks"); 
    438628 
     629        // correct, official signature should succeed 
    439630        { 
    440631                // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html 
     
    458649        } 
    459650 
     651        // modified signature should fail 
    460652        { 
    461653                // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html 
     
    479671        } 
    480672 
    481         { 
    482                 HTTPRequest request(HTTPRequest::Method_GET, "/nonexist"); 
    483                 request.SetHostName("quotes.s3.amazonaws.com"); 
    484                 request.AddHeader("Date", "Wed, 01 Mar  2006 12:00:00 GMT"); 
    485                 request.AddHeader("Authorization", "AWS 0PN5J17HBGZHT7JJ3X82:0cSX/YPdtXua1aFFpYmH1tc0ajA="); 
    486  
     673        // S3Client tests 
     674        { 
    487675                S3Simulator simulator; 
    488                  
    489                 CollectInBufferStream response_buffer; 
    490                 HTTPResponse response(&response_buffer); 
    491                  
    492                 simulator.Handle(request, response); 
     676                S3Client client(&simulator, "johnsmith.s3.amazonaws.com", 
     677                        "0PN5J17HBGZHT7JJ3X82", 
     678                        "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"); 
     679                 
     680                HTTPResponse response = client.GetObject("/photos/puppy.jpg"); 
     681                TEST_EQUAL(200, response.GetResponseCode()); 
     682                std::string response_data((const char *)response.GetBuffer(), 
     683                        response.GetSize()); 
     684                TEST_EQUAL("omgpuppies!\n", response_data); 
     685 
     686                response = client.GetObject("/nonexist"); 
    493687                TEST_EQUAL(404, response.GetResponseCode()); 
    494688        } 
Note: See TracChangeset for help on using the changeset viewer.