1

I've facing a pretty odd issue. I'm attempting to upload an image to a PHP script. The build compiles without errors, which is what I had expected, but when the session is actually completed, it returns with an HTTP error 403. I'm aware that 403 is "Forbidden", but I have no idea is to what might be causing the error. Here's the session.

func uploadFile(fileData: NSData) {
    var request: NSMutableURLRequest = NSMutableURLRequest(URL: NSURL(string: "https://www.codekaufman.com/file.php")!)
    request.HTTPMethod = "POST"

    let session = NSURLSession(configuration: .defaultSessionConfiguration())

    let uploadTask = session.uploadTaskWithRequest(request, fromData: fileData, completionHandler:{
        data, response, error in
        if error != nil {
            println(error)
            return
        }

        println(response.description)
        println()

        var err: NSError?
        var receivedData: [String: AnyObject]!
        receivedData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? [String: AnyObject]

        if(receivedData != nil) {
            println(receivedData)
        } else {
            println("No data recieved.")
        }

    })

    uploadTask.resume()
}

Here's the PHP script, it's nothing special.

<?php

error_reporting(E_ALL);
ini_set('display errors', 1);

if(isset($_FILES['file'])) {
    echo json_encode(array('status' => 'true'));   
} else {
    echo json_encode(array('status' => 'false'));  
}

?>

Lastly here's the response.

<NSHTTPURLResponse: 0x7ff4f062bd10> { URL: https://www.codekaufman.com/file.php } { status code: 403, headers {
    "Accept-Ranges" = bytes;
    Connection = "Keep-Alive";
    "Content-Length" = 1551;
    "Content-Type" = "text/html";
    Date = "Fri, 13 Feb 2015 08:05:55 GMT";
    "Keep-Alive" = "timeout=10, max=200";
    Server = Apache;
} }

I should note the console displays "No data received." I've asked around in the SO chat room 'NSChat', and we've played around with attempting to fix it. Although we didn't fix it, we have discovered that it does NOT receive an auth challenge.

Furthermore, I have no idea what to do. Any help is much appreciated. Thanks.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Jeffrey
  • 1,271
  • 2
  • 15
  • 31
  • I notice that in addition to your 403 status code, there is a `Content-Length` of `1551`, suggesting that the `data` parameter might contain something useful. So try something like `if let string = NSString(data: data, encoding: NSUTF8StringEncoding) { println(string) }`. Often it contains some HTML which provides further information regarding the problem. – Rob Feb 15 '15 at 06:19
  • @Rob Oi, my mistake. Typically I do that. And yes, the data does contain something... the whole 403 page with inline css. :P – Jeffrey Feb 15 '15 at 06:43
  • Does your server have any security extensions installed, like suhosin or modsecurity? Either of those might be seeing your POST request as suspicious in some way and blocking it with a 403. Checked your server error logs? That's where I'd look to diagnose this kind of issue... – Matt Gibson Feb 15 '15 at 09:28
  • Also, given that you're using `$_FILES` on the server side, you should be sending the file data as `mulitpart/form-data`, or it won't work anyway, I believe. You should send it similarly to [this Objective C answer](http://stackoverflow.com/questions/24250475/post-multipart-form-data-with-objective-c), or just read raw binary data on the PHP side rather than using `$_FILES`, similarly to [this answer](http://stackoverflow.com/a/28269901/300836). (Personally, I send as JSON with the binary base64 encoded and decode it back out again in the PHP...) – Matt Gibson Feb 15 '15 at 09:36
  • @MattGibson I must not, I do have a working system that sends the files through an SessionDataTask, using multipart/form-data - but I'm not sure how I would set it up for the upload task, as you also set the boundary under the "Content-Type" header, and if I understand correctly, it would be ignored. – Jeffrey Feb 15 '15 at 21:05

1 Answers1

0

Unfortunately, while I cannot say why this works, I found that adding the line

request.addValue("application/form-data", forHTTPHeaderField: "Content-Type")

solved all of my issues. The server responds with 200, and I receive the JSON response as expected. Thanks to those who had attempted to help, although not answering my question, you guys brought some important points to my attention.

Jeffrey
  • 1,271
  • 2
  • 15
  • 31