HTTP Request failing, help please

Hey guys,

So I am trying to have my app communicate with a server to check promo codes against a database to unlock the full app. I had this working a month ago, and now all the sudden its giving me issues. I know the server doesn’t have issues because I when I send the request via a web browser it returns that the promo code is valid and what not. The HTTP call also works when done from the simulator. It is on the device that I see issues… here is the request that I am doing (which I dumbed down to just give me back a response…

[lua]local rw_app_id = 1
local code = 0
local device_id = system.getInfo( “name” )

local function textListener( event )
code = event.text
end

local networkListener = function( event )
if ( event.isError ) then
local networkErrorAlert = native.showAlert( “Response”, event.response, { “OK” })

else

local networkErrorAlert = native.showAlert( “Response”, event.response, { “OK” })
end

end

local callDatabase = function( event )

if event.phase == “release” then
print(“call made”)
network.request( “http://***********/promos/index.php?rw_app_id=” … rw_app_id … “&code=” … code … “&device_id=” … device_id, “GET”, networkListener )

end
end[/lua]

I put ***** where the IP address is. So again, works in web browser, and in the simulator but on the device it doesn’t work… If necessary I can put up the code of the index.php file its hitting

Any thoughts of what might be wrong here? really frustrating. Also even when the call fails in the app, on my database side I can see that the app did hit the database, but I still get a fail response in the app
[import]uid: 19620 topic_id: 30174 reply_id: 330174[/import]

I’m going to take a stab that the problem has something to do with your device id. As a test try to changing this:

[lua]local device_id = system.getInfo( “name” )[/lua]

to this

[lua]local device_id = “FakeDeviceName”[/lua]

and then run it on your device. [import]uid: 147305 topic_id: 30174 reply_id: 120854[/import]

Thanks for the response. So I changed as you suggested and on my android device I get a response of “Bad Request” still. When I test on a iPhone I get a response of “Bad URL”. Both of which I believe are a error code 400. hmm any other ideas? [import]uid: 19620 topic_id: 30174 reply_id: 120871[/import]

Actually @budershank may be on to something.

What value is system.getInfo(“name”) returning?

Does it have spaces or non-letter/number character’s like an apostrophe i.e. “Rob’s iPad”

HTTP URL’s cannot have spaces in them, and many of the keyboard symbols like quotes and such have to be URL Encoded before transmitting them to the webserver. Basically those symbols have to be converted into their hexadecimal ASCII value and preceded by a %. For instance a space become %20.

You can use these functions to code/decode the data:

function url\_encode(str)  
 if (str) then  
 str = string.gsub (str, "\n", "\r\n")  
 str = string.gsub (str, "([^%w])",  
 function (c) return string.format ("%%%02X", string.byte(c)) end)  
 str = string.gsub (str, " ", "+")  
 end  
 return str   
end  
  
 function url\_decode(str)  
 str = string.gsub (str, "+", " ")  
 str = string.gsub (str, "%%(%x%x)",  
 function(h) return string.char(tonumber(h,16)) end)  
 str = string.gsub (str, "\r\n", "\n")  
 return str  
 end  
  

Taken from: http://lua-users.org/wiki/StringRecipes

[import]uid: 19626 topic_id: 30174 reply_id: 120873[/import]

Thanks for that code robmiracle. Unfortunately I made the change as suggested above so in my last attempt I had hard coded “FakeDeviceName” for my device_id and I am seeing the same issue. [import]uid: 19620 topic_id: 30174 reply_id: 120875[/import]

Ok, so to try a bare bones request I changed my request to simply be “http://***********/promos/index.php” In my browser this returns invalid request, which is normal because I am not sending the information it needs. Still on the device I get “Bad Request”… [import]uid: 19620 topic_id: 30174 reply_id: 120878[/import]

what happens if you send it the information you need?

Do this:

local callDatabase = function( event )  
   
 if event.phase == "release" then  
 print("call made")  
 local URL = "http://\*\*\*\*\*\*\*\*\*\*\*/promos/index.php?rw\_app\_id=" .. rw\_app\_id .. "&code=" .. code .. "&device\_id=" .. device\_id  
 print(URL)  
 network.request( URL, "GET", networkListener )  
   
 end  
end  

Then feed that exact URL to a web browser and what do you get?
[import]uid: 19626 topic_id: 30174 reply_id: 120879[/import]

Ugh, same results…

On my PC web browser it works fine, even in the web browser on my phone it works, but inside the corona app it send back “Bad Request”. It also works from the Corona simulator… Would it be helpful if you could look at the code of my “index.php”? [import]uid: 19620 topic_id: 30174 reply_id: 120880[/import]

[php]

<?php
// Helper method to get a string description for an HTTP status code // From http://www.gen-x-design.com/archives/create-a-rest-api-with-php/ function getStatusCodeMessage($status) { // these could be stored in a .ini file and loaded // via parse\_ini\_file()... however, this will suffice // for an example $codes = Array( 100 =\> 'Continue', 101 =\> 'Switching Protocols', 200 =\> 'OK', 201 =\> 'Created', 202 =\> 'Accepted', 203 =\> 'Non-Authoritative Information', 204 =\> 'No Content', 205 =\> 'Reset Content', 206 =\> 'Partial Content', 300 =\> 'Multiple Choices', 301 =\> 'Moved Permanently', 302 =\> 'Found', 303 =\> 'See Other', 304 =\> 'Not Modified', 305 =\> 'Use Proxy', 306 =\> '(Unused)', 307 =\> 'Temporary Redirect', 400 =\> 'Bad Request', 401 =\> 'Unauthorized', 402 =\> 'Payment Required', 403 =\> 'Forbidden', 404 =\> 'Not Found', 405 =\> 'Method Not Allowed', 406 =\> 'Not Acceptable', 407 =\> 'Proxy Authentication Required', 408 =\> 'Request Timeout', 409 =\> 'Conflict', 410 =\> 'Gone', 411 =\> 'Length Required', 412 =\> 'Precondition Failed', 413 =\> 'Request Entity Too Large', 414 =\> 'Request-URI Too Long', 415 =\> 'Unsupported Media Type', 416 =\> 'Requested Range Not Satisfiable', 417 =\> 'Expectation Failed', 500 =\> 'Internal Server Error', 501 =\> 'Not Implemented', 502 =\> 'Bad Gateway', 503 =\> 'Service Unavailable', 504 =\> 'Gateway Timeout', 505 =\> 'HTTP Version Not Supported' ); return (isset($codes[$status])) ? $codes[$status] : ''; } // Helper method to send a HTTP response code/message function sendResponse($status = 200, $body = '', $content\_type = 'text/html') { $status\_header = 'HTTP/1.1 ' . $status . ' ' . getStatusCodeMessage($status); header($status\_header); header('Content-type: ' . $content\_type); echo $body; } class RedeemAPI { private $db; // Constructor - open DB connection function \_\_construct() { $this-\>db = new mysqli('localhost', '\*user', '\*password', '\*database'); $this-\>db-\>autocommit(FALSE); } // Destructor - close DB connection function \_\_destruct() { $this-\>db-\>close(); } // Main method to redeem a code function redeem() { // Check for required parameters if (isset($\_GET["rw\_app\_id"]) && isset($\_GET["code"]) && isset($\_GET["device\_id"])) { // Put parameters into local variables $rw\_app\_id = $\_GET["rw\_app\_id"]; $code = $\_GET["code"]; $device\_id = $\_GET["device\_id"]; // Look up code in database $user\_id = 0; $stmt = $this-\>db-\>prepare('SELECT id, unlock\_code, uses\_remaining FROM rw\_promo\_code WHERE rw\_app\_id=? AND code=?'); $stmt-\>bind\_param("is", $rw\_app\_id, $code); $stmt-\>execute(); $stmt-\>bind\_result($id, $unlock\_code, $uses\_remaining); while ($stmt-\>fetch()) { break; } $stmt-\>close(); // Bail if code doesn't exist if ($id \<= 0) { sendResponse(400, 'Invalid code'); return false; } // Bail if code already used if ($uses\_remaining \<= 0) { sendResponse(403, 'Code already used'); return false; } // Check to see if this device already redeemed $stmt = $this-\>db-\>prepare('SELECT id FROM rw\_promo\_code\_redeemed WHERE device\_id=? AND rw\_promo\_code\_id=?'); $stmt-\>bind\_param("si", $device\_id, $id); $stmt-\>execute(); $stmt-\>bind\_result($redeemed\_id); while ($stmt-\>fetch()) { break; } $stmt-\>close(); // Bail if code already redeemed if ($redeemed\_id \> 0) { sendResponse(403, 'Code already used'); return false; } // Add tracking of redemption $stmt = $this-\>db-\>prepare("INSERT INTO rw\_promo\_code\_redeemed (rw\_promo\_code\_id, device\_id) VALUES (?, ?)"); $stmt-\>bind\_param("is", $id, $device\_id); $stmt-\>execute(); $stmt-\>close(); // Decrement use of code $this-\>db-\>query("UPDATE rw\_promo\_code SET uses\_remaining=uses\_remaining-1 WHERE id=$id"); $this-\>db-\>commit(); // Return unlock code, encoded with JSON $result = array( "unlock\_code" =\> $unlock\_code, ); sendResponse(200, json\_encode($result)); return true; } sendResponse(400, 'Invalid request'); return false; } } // This is the first thing that gets called when this page is loaded // Creates a new instance of the RedeemAPI class and calls the redeem method $api = new RedeemAPI; $api-\>redeem(); ?\> [/php] Note: I removed user, password and database names from the above code [import]uid: 19620 topic\_id: 30174 reply\_id: 120882[/import]

Another note, did just a simple request to “http://www.google.com” and I am getting a correct response. Must be an issue with my server in some way? Though I don’t understand how communication from a web browser http call is different from coronas… [import]uid: 19620 topic_id: 30174 reply_id: 120888[/import]

I’d like to see the URL from the print statement in it’s entirety (you can scrub the actual address with *** like you have been. I just need to see the query string.
[import]uid: 19626 topic_id: 30174 reply_id: 120889[/import]

Sure, here is what the print statement is showing for the URL

Photobucket [import]uid: 19620 topic_id: 30174 reply_id: 120891[/import]

I don’t see anything immediately wrong with your PHP code. I don’t return status codes that way. I prefer to let the server return what it wants and I return my codes as part of my data that gets JSON encoded.

You may want to have more descriptive return messages for your error conditions. [import]uid: 19626 topic_id: 30174 reply_id: 120892[/import]

Yea unfortunately I am a super noob with php, this is basically from a tutorial that I followed so I myself don’t understand really well every detail of the index.php. Would it be a easy change to do as you suggest and allow the server to send more detailed message? How would I need to change the index.php to do so?
[import]uid: 19620 topic_id: 30174 reply_id: 120894[/import]

This may be far-fetched, but maybe it’s a header issue? Maybe the device isn’t setting the header to something PHP is happy with. I am not sure what the header should be as I have very limited experience with PHP.

I vaguely remember having issues when I setup my first network.request and it was header & PHP related. Unfortunately I don’t remember how I solved it as I dumped PHP soon after and starting using parse.com. [import]uid: 56820 topic_id: 30174 reply_id: 120899[/import]

Hmm yea, I just don’t understand why the Corona simulator and the built app are not doing the exact same thing in regards to the http request [import]uid: 19620 topic_id: 30174 reply_id: 120903[/import]

So I ended up trying to do a POST rather than GET

[lua]local callDatabase = function( event )

if event.phase == “release” then
print(“call made”)
local URL = “http://************/promos/index.php”
local postData = “rw_app_id=” … rw_app_id … “&code=” … code … “&device_id=” … device_id
local params = {}
params.body = postData

print(URL)
print(params.body)
network.request( URL, “POST”, networkListener, params )

end
end[/lua]

With this setup now if I send a correct promo code that is in my database, it returns as it should with the unlock code for my app. But when I send an invalid code or a code thats been used already, I get sent back “Bad Request” (for invalid code) and “Forbidden” (for code already used)… So its working, but not sure why the response its sending back isn’t correct like it is shown in the php. “Code already used” etc… [import]uid: 19620 topic_id: 30174 reply_id: 120919[/import]

I’m going to take a stab that the problem has something to do with your device id. As a test try to changing this:

[lua]local device_id = system.getInfo( “name” )[/lua]

to this

[lua]local device_id = “FakeDeviceName”[/lua]

and then run it on your device. [import]uid: 147305 topic_id: 30174 reply_id: 120854[/import]

Thanks for the response. So I changed as you suggested and on my android device I get a response of “Bad Request” still. When I test on a iPhone I get a response of “Bad URL”. Both of which I believe are a error code 400. hmm any other ideas? [import]uid: 19620 topic_id: 30174 reply_id: 120871[/import]

Actually @budershank may be on to something.

What value is system.getInfo(“name”) returning?

Does it have spaces or non-letter/number character’s like an apostrophe i.e. “Rob’s iPad”

HTTP URL’s cannot have spaces in them, and many of the keyboard symbols like quotes and such have to be URL Encoded before transmitting them to the webserver. Basically those symbols have to be converted into their hexadecimal ASCII value and preceded by a %. For instance a space become %20.

You can use these functions to code/decode the data:

function url\_encode(str)  
 if (str) then  
 str = string.gsub (str, "\n", "\r\n")  
 str = string.gsub (str, "([^%w])",  
 function (c) return string.format ("%%%02X", string.byte(c)) end)  
 str = string.gsub (str, " ", "+")  
 end  
 return str   
end  
  
 function url\_decode(str)  
 str = string.gsub (str, "+", " ")  
 str = string.gsub (str, "%%(%x%x)",  
 function(h) return string.char(tonumber(h,16)) end)  
 str = string.gsub (str, "\r\n", "\n")  
 return str  
 end  
  

Taken from: http://lua-users.org/wiki/StringRecipes

[import]uid: 19626 topic_id: 30174 reply_id: 120873[/import]