mercredi 5 août 2015

Calculate payload hash using SwiftHTTP

I'm writing a program for the MAC (OS X) and need to retrieve and send objects to AWS S3. Amazon provides a fine library for iOS but nothing that I could figure out how to use without a LOT of recompiling, etc.

I've settled on using the SwiftHTTP library (very impressed btw). It seems to work very well for GET operations. I am having a challenge on the PUT side however.

The AWS v4 signing protocol requires that a SHA256 hash of the payload be provided as a header value - which means I have to compute that payload before I create the HTTP request.

However, it looks like SwiftHTTP is adding some other stuff to the payload, thereby messing up my hash. I'm fairly certain the SHA256 algorithm is correct since it gives the same values from the AWS samples.

Sample code below:

// build our headers
var ourHeaders: [String: String] = [String: String]()
ourHeaders["Host"] = s3url
ourHeaders["x-amz-date"] = MakeAWSxDateString(NSDate())

let payloadHash: String = SHA256ToHex(objectString)
ourHeaders["x-amz-content-sha256"] = payloadHash

// add the headers into the SwiftHTTP structures
var request = HTTPTask()
request.requestSerializer = HTTPRequestSerializer()
for (key, value) in ourHeaders {
    request.requestSerializer.headers[key] = value
}

// compute our authorization string
var authString: String = MakeAuthorizationString("PUT", url: s3url, absPath: absPath, headers_us: ourHeaders, payloadhash: payloadHash)
request.requestSerializer.headers["Authorization"] = authString

// convert the in memory string to a format that SwiftHTTP wants    
let objectValueD: NSData = objectValue.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!

// make the call to upload the object
request.PUT(
    "http://" + s3url + absPath, 
    parameters: ["file": HTTPUpload(data: objectValueD, fileName: objectName, mimeType: "application/octet-stream") ],
    completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
        let descr: String = response.description
        println("Description: " + descr)
    }
    if let data = response.responseObject as? NSData {
        if let str = NSString(data: data, encoding: NSUTF8StringEncoding) {
            // do the xml parsing of 'str' here...
        }
    }
})

I'm pretty sure I'm missing something obvious. But after following the source code for SwiftHTTP, it looks like SwiftHTTP always creates a multipart envelope for the data, hence a different payload (with a different hash).




Aucun commentaire:

Enregistrer un commentaire