Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending multipart POST from iOS and reading parameters in PHP $_POST?

I'm trying to send a multi-line post from an iPhone/iPad to a php service, the problem is that for some reason, the POST Content-Type seems to be application/x-www-form-urlenconded, ( I found out this using Wireshark )

This is actually a snippet of the Wireshark POST packet capture:

    **Content-Type: application/x-www-form-urlencoded\r\n**
    Content-Length: 324\r\n
        [Content length: 324]
    Connection: keep-alive\r\n
    \r\n
    [Full request URI: http://my.server.com/mobile/tools/authentication]
Line-based text data: application/x-www-form-urlencoded
    --0xKhTmLbOuNdArY\r\n
    Content-Disposition: form-data; name="login"\r\n
    \r\n
    [email protected]\r\n
    --0xKhTmLbOuNdArY\r\n
    Content-Disposition: form-data; name="password"\r\n
    \r\n
    somepassword\r\n
    --0xKhTmLbOuNdArY\r\n
    \r\n
    --0xKhTmLbOuNdArY--\r\n

The problem is that in the server I'm trying to read the login and password variables from this POST request, but it's not possible since I think php thinks the POST request is x-www-form-urlencoded, so if I setup authentication.php to do:

<?php
echo("<pre>")
print_r($_POST)
echo("</pre>")
?>

I get this:

<pre>Array\n
(\n
    [--0xKhTmLbOuNdArY\r\n
Content-Disposition:_form-data;_name] => "login"\r\n
\r\n
[email protected]\r\n
--0xKhTmLbOuNdArY\r\n
Content-Disposition: form-data; name="password"\r\n
\r\n
somepassword\r\n
--0xKhTmLbOuNdArY\r\n
\r\n
--0xKhTmLbOuNdArY--\r\n
\n
)\n
</pre>

This is clearly not good, since If I send a request using this simple html form:

<FORM action="http://my.server.com/mobile/tools/authentication.php" method="post">
   <P>
   <LABEL for="login">E-mail: </LABEL>
             <INPUT type="text" name="login"><BR>
   <LABEL for="password">pass: </LABEL>
             <INPUT type="text" name="password"><BR>
   <INPUT type="submit" value="Send"> <INPUT type="reset">
   </P>
</FORM>

I get this Wireshark trace as expected from a form:

    Content-Type: application/x-www-form-urlencoded\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
    Accept-Encoding: gzip,deflate,sdch\r\n
    Accept-Language: en-US,en;q=0.8\r\n
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n
    Cookie: PHPSESSID=tpp10pbrdkkf5dg9qprlamfuu2\r\n
    \r\n
    [Full request URI: http://mymed2.sophia.inria.fr/mobile/tools/authentication.php]
Line-based text data: application/x-www-form-urlencoded
    login=hello%40hello.com&password=somepassword

And this text output from the print_r($_POST) in authentication.php

<pre>Array\n
(\n
    [login] => [email protected]\n
    [password] => somepassword\n
)\n
</pre>

This is the way I'm crafting the POST request in Objective-C and Cocoa

- (NSMutableURLRequest *) POSTRequestWithURL:(NSURL *)url andDataDictionary:(NSDictionary *) dictionary
{
    // Create a POST request
    NSMutableURLRequest *myMedRequest = [NSMutableURLRequest requestWithURL:url];
    [myMedRequest setHTTPMethod:@"POST"];

    // Add HTTP header info
    // Note: POST boundaries are described here: http://www.vivtek.com/rfc1867.html
    // and here http://www.w3.org/TR/html4/interact/forms.html
    NSString *POSTBoundary = [NSString stringWithString:@"0xKhTmLbOuNdArY"];
    [myMedRequest addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@\r\n", POSTBoundary] forHTTPHeaderField:@"Content-Type"];

    // Add HTTP Body
    NSMutableData *POSTBody = [NSMutableData data];
    [POSTBody appendData:[[NSString stringWithFormat:@"--%@\r\n",POSTBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

    // Add Key/Values to the Body
    NSEnumerator *enumerator = [dictionary keyEnumerator];
    NSString *key;

    while ((key = [enumerator nextObject])) {
        [POSTBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
        [POSTBody appendData:[[NSString stringWithFormat:@"%@", [dictionary objectForKey:key]] dataUsingEncoding:NSUTF8StringEncoding]];
        [POSTBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", POSTBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    }

    // Add the closing -- to the POST Form
    [POSTBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", POSTBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 

    // Add the body to the myMedRequest & return
    [myMedRequest setHTTPBody:POSTBody];
    return myMedRequest;
}

As you see, in the beginning I do:

    [myMedRequest addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@\r\n", POSTBoundary] forHTTPHeaderField:@"Content-Type"];

But in the previous Wireshark trace logs, the POST packet was being viewed as Content-Type: application/x-www-form-urlencoded, maybe I'm doing something else wrong ?

Thanks :)

EDIT: I want to avoid external frameworks like ASIHTTPRequest, by the way, ASIHTTPRequest development has been abandoned by the lead developer as stated here

like image 418
Goles Avatar asked Oct 12 '11 10:10

Goles


1 Answers

Ok, since I couldn't find a solution without external libraries I fixed my code and open sourced it, in case anyone want's to use it.

The problem on the code I posted was the \r\n on the line

[myMedRequest addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@\r\n", POSTBoundary] forHTTPHeaderField:@"Content-Type"];

Removing that fixed everything.

Hope this helps someone else :)

like image 189
Goles Avatar answered Sep 27 '22 18:09

Goles