2

All

This is a problem which happens rarely. In fact I had to spend a lot of time to reproduce it but here it is anyways.

I am using ASIHTTPRequest to get some data from my server. I throw error for anything apart from those having responseStatusCode == 200. My server returns some messages.

What I noticed is, that sometimes, depending on my wireless connection (on laptop simulator usage), the ones which needs authentication, ASIHttpRequest returns response of 200, but the responseData is something like the following instead of the messages from my server

<HTML><HEAD><TITLE>Cisco Systems Inc. Web Authentication Redirect</TITLE><META http-equiv="Cache-control" content="no-cache"><META http-equiv="Pragma" content="no-cache"><META http-equiv="Expires" content="-1"><META http-equiv="refresh" content="1; URL=https://webauth-redirect.oracle.com/login.html?redirect=17.22.111.222/scripts_dummy/messagesx.php"></HEAD></HTML>

Is this correct? If the message from the server was not received should not the responseStatusCode be something other than 200

How do I go about handling this kind of situation? meaning after checking responseStatusCode == 200 does not seem to be good enough. This was just an example. In other wireless regions, different garbage is printed out.

UPDATE Not sure if this has any role to play but I have

request.shouldUseRFC2616RedirectBehaviour = YES; // where request is ASIHTTPRequest
mbh
  • 3,302
  • 2
  • 22
  • 24

3 Answers3

3

That's not ASIHTTPRequest or your client code's fault. That's the server expecting the client to be a web browser and sending it a a meta refresh redirect (that is, an HTML page with a redirect embedded in it) rather than an HTTP 30x, which ASIHTTP would have handled for you.

This is an excellent example of how meta refresh has been abused: it was meant to refresh the current page, but people started using it to send the client somewhere else, which was what HTTP 30x was already designed for. Googling for "meta refresh vs 301 redirect" will give you plenty of blog posts making the arguments.

In your case, unless you can get your server to behave friendlier to non-browser clients, you'll need to check for this condition yourself when response code is 200, parse out the redirect and re-issue the request yourself.

ckhan
  • 4,771
  • 24
  • 26
  • thanks a lot for your response. When you say "you'll need to check for this condition yourself", would you happen to have any idea how I can use ASIHTTPRequest to do that? – mbh May 06 '12 at 00:46
  • The result of the request (as you probably know) is in `request.responseString` - you'll need to search that string for the `http-equiv="refresh"` and make a new ASIHTTPRequest to the destination in `URL=`. – ckhan May 06 '12 at 00:59
  • Ok I didn't really like that solution. Looked like a hack. What I am thinking is to send a special key/value pair from the server in the response header. Say header('My App:' . 'success'); And then check for the presence of that key/value pair in the responseHeaders from ASIhttpRequest. This way I should be always safe? – mbh May 08 '12 at 01:01
  • If *you* have control of the server, just send a 301! If you don't have control of the server, not sure I'm following you. – ckhan May 08 '12 at 03:30
1

After thinking about this for a few, I've come up with an alternate strategy. Content type will be preserved and should not be muddled with.

You should be able to use the content type as a flag that you are receiving a proxy injected page. Set a content type parameter then have your app key off that parameter. Any responses that don't have the parameter are invalid.

$content_type = 'text/html; FooCorp-MyApp=true'

BTW: why are you using a content type of text/html if you don't properly support HTML processing. Meta refresh should be a part of any HTML engine. If you don't need HTML, you may want do consider using a data specific content type like XML, YAML, or JSON.


The question has been raised, "is that valid?"

From RFC 2616: 3.7 Media Types

The type, subtype, and parameter attribute names are case- insensitive. Parameter values might or might not be case-sensitive, depending on the semantics of the parameter name. Linear white space (LWS) MUST NOT be used between the type and subtype, nor between an attribute and its value. The presence or absence of a parameter might be significant to the processing of a media-type, depending on its definition within the media type registry.

Note that some older HTTP applications do not recognize media type parameters. When sending data to older HTTP applications, implementations SHOULD only use media type parameters when they are required by that type/subtype definition.

To me, the takeaway from that is don't send non-standard parameters to older clients. In context, it means you're safe if you are sending it to any client made since 2000.

Community
  • 1
  • 1
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
  • Thanks for the response. Now I get a chance to upvote and mark this right. You deserved it based on your comments earlier as well. You were right that I should have set the content type as "application/json" because thats what I am expecting. So now as a final solution I will do both the $content_type = 'application/json; FooCorp-MyApp=true' and the custome header thingy and do a OR check. That way I should be the safest. One question though...is it ok to put non-registered FooCorp-MyApp=true in the content type? – mbh May 16 '12 at 16:53
  • I updated my answer. BTW: just checking for 'application/json' should be good enough. The proxy would be a real bastard if it sent an HTML document with a Content-Type of 'application/json'. – Jeffery Thomas May 16 '12 at 17:21
0

I ended up passing a special key/value pair in my response header to make sure the client understands the response is from my server and not from some intermediary redirection.

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);
   $value = 'success';
   header('myApp:' . $value); // --> I will always check in my client that the key myApp has the value success

echo $body;
}
mbh
  • 3,302
  • 2
  • 22
  • 24
  • This solution could cause you problems in the future. Some proxies filter out unknown headers. Unless you have tight control over the network environment, you can't always rely on custom headers. – Jeffery Thomas May 12 '12 at 02:32
  • In addition, you should always begin non-standard headers with 'x-'. Something like 'x-MyApp:'. $value would do nicely. – Jeffery Thomas May 12 '12 at 02:34
  • True. Is there a cleaner alternative you can propose? – mbh May 16 '12 at 03:49
  • Also the X- is deprecated. See http://stackoverflow.com/questions/3561381/custom-http-headers-naming-conventions – mbh May 16 '12 at 04:03
  • WTF: [draft-ietf-appsawg-xdash-05](http://tools.ietf.org/html/draft-ietf-appsawg-xdash-05) is a nightmare. Their answer is to pollute the global namespace because of piss poor implementations. Appendix B points out the silliness. I guess I would still follow the recommendation and use 'FooCorp-MyApp' (where FooCorp is your company name). – Jeffery Thomas May 16 '12 at 13:02