BUG: SoundCloud API should be case insensitive

129 views
Skip to first unread message

RF

unread,
Feb 11, 2011, 11:15:56 AM2/11/11
to SoundCloudAPI
as per the HTTP1.1 spec:
http://tools.ietf.org/html/rfc2616#section-4.2

"Field names are case-insensitive."

e.g. This works
curl https://api.soundcloud.com/oauth2/token\
-d 'client_id=xxx'\
-d 'grant_type=authorization_code'\
-d 'client_secret=yyy'\
-d 'redirect_uri=appname://oauth-thing'\
-d 'code=zzz'

but this does not
curl https://api.soundcloud.com/oauth2/token\
-d 'Client_id=xxx'\
-d 'Grant_type=authorization_code'\
-d 'Client_secret=yyy'\
-d 'Redirect_uri=appname://oauth-thing'\
-d 'Code=zzz'

(you get {"error":"invalid_client"})

I don't personally care, but this non compliance means you can't use
the built in iOS classes to talk to SoundCloud as the url request
class stupidly (but legally!) upper cases the first letter of http
header fields.

This probably isn't the right place to log a bug, but it would be nice
to get a fix for this.

Cheers,
RF.

Robert Stevenson-Leggett

unread,
Feb 11, 2011, 12:10:02 PM2/11/11
to soundc...@googlegroups.com
> stupidly (but legally!) upper cases the first letter of http
> header fields.

Interesting - I think this my problem - I keep getting invalid client
on windows using curl and fiddler2 - does this sound like these pieces
of software could uppercase the post variable names?

Rob
----
twitter: rsleggett

> --
> You received this message because you are subscribed to the Google Groups "SoundCloudAPI" group.
> To post to this group, send email to soundc...@googlegroups.com.
> To unsubscribe from this group, send email to soundcloudap...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/soundcloudapi?hl=en.
>
>

RF

unread,
Feb 11, 2011, 12:32:35 PM2/11/11
to SoundCloudAPI

On Feb 11, 8:15 am, RF <rfist...@gmail.com> wrote:
> as per the HTTP1.1 spec:http://tools.ietf.org/html/rfc2616#section-4.2
>
> "Field names are case-insensitive."
>
> e.g. This works
> curlhttps://api.soundcloud.com/oauth2/token\
>   -d 'client_id=xxx'\
>   -d 'grant_type=authorization_code'\
>   -d 'client_secret=yyy'\
>   -d 'redirect_uri=appname://oauth-thing'\
>   -d 'code=zzz'
>
> but this does not
> curlhttps://api.soundcloud.com/oauth2/token\
>   -d 'Client_id=xxx'\
>   -d 'Grant_type=authorization_code'\
>   -d 'Client_secret=yyy'\
>   -d 'Redirect_uri=appname://oauth-thing'\
>   -d 'Code=zzz'
>
> (you get {"error":"invalid_client"})
>
> I don't personally care, but this non compliance means you can't use
> the built in iOS classes to talk to SoundCloud as the url request
> class stupidly (but legally!) upper cases the first letter of http
> header fields.
>
> This probably isn't the right place to log a bug, but it would be nice
> to get a fix for this.

For now I've worked around it by passing the fields in the URL (first
double checking that URL actually gets encrypted in https).

But still it'd would be nice if the API were fixed... and if Apple
didn't do this kind of thing.

RF.

Ullrich Schäfer

unread,
Feb 11, 2011, 5:03:32 PM2/11/11
to soundc...@googlegroups.com, SoundCloudAPI
We're using Apples own NSURLConnection in the Cocoa API wrapper without problems. Can you use Charles to compare a working & a not working Request?

-Ullrich

RF

unread,
Feb 13, 2011, 6:04:43 AM2/13/11
to SoundCloudAPI


On Feb 11, 11:03 pm, Ullrich Schäfer <ullr...@soundcloud.com> wrote:
> We're using Apples own NSURLConnection in the Cocoa API wrapper without problems. Can you use Charles to compare a working & a not working Request?

Your NSURLConnection implementation only works because you're passing
the header fields as multipart form data via [NSMutableURLRequest
setHTTPBodyStream] and NSMutableURLRequest doesn't mess around
multipart form data.

e.g.

"Content-Type" = "multipart/form-data; boundary=------------nx-
oauth216807";
"User-Agent" = "MacTestApp/1.0; SCSoundCloudAPI/2.0b6; Mac/i386;
Mac OS X/10.6.6; Darwin/10.6.0";
--------------nx-oauth216807
Content-Disposition: form-data; name="client_id"
xxx
--------------nx-oauth216807
Content-Disposition: form-data; name="code"
yyy

and so on.

Still, it would be really nice if the obvious implementation "just
worked":

NSMutableURLRequest* request = [[NSMutableURLRequest new]
autorelease];
[request setHTTPMethod:@"POST"];

NSDictionary* headers = [NSDictionary dictionaryWithObjectsAndKeys:
SCAppClientID, @"client_id",
SCAppClientSecret, @"client_secret",
@"authorization_code", @"grant_type",
SCAppURIRedirect, @"redirect_uri",
auth_code, @"code",
nil];

[request setURL:[NSURL URLWithString:SCAuthTokenURL]];
[request setAllHTTPHeaderFields:headers];

[NSURLConnection connectionWithRequest:request delegate:self];

So whaddya say? How about making Sound Cloud HTTP 1.1 compliant?

It'll be good for Sound Cloud.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2

Regards,
RF.

Sean Treadway

unread,
Feb 13, 2011, 8:02:27 AM2/13/11
to soundc...@googlegroups.com
Hi RF,

I'll address the subject, as I can't speak to what the Apple libraries
do to URL data.

It seems there is some confusion between HTTP header fields, and
application/x-www-form-urlencoded key value pairs.

You are correct that the header key value pairs part of an HTTP 1.1
message (after the request line and before the body) should be handled
as case-insensitive. In our servers, we do treat these headers as
case-insensitive.

The curl example you gave does not add any headers (that's the -H
parameter), it only builds a URL encoded body for the POST you are
issuing. The documentation for the '-d' parameter in the curl man
page:

"
(HTTP) Sends the specified data in a POST request to the HTTP server,
in the same way that a browser does when a user has filled in an
HTML form and presses the submit button. This will cause curl to pass
the data to the server using the content-type
application/x-www-form-urlencoded.
...
Thus, using '-d name=daniel -d skill=lousy' would generate
a post chunk that looks like 'name=daniel&skill=lousy'.
"

So your two requests would look like this:

POST /oauth2/token HTTP/1.1
User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7
OpenSSL/0.9.8l zlib/1.2.3
Host: api.soundcloud.com
Accept: */*
Content-Length: 105
Content-Type: application/x-www-form-urlencoded

client_id=xxx&grant_type=authorization_code&client_secret=yyy&redirect_uri=appname://oauth-thing&code=zzz

Compared to:

POST /oauth2/token HTTP/1.1
User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7
OpenSSL/0.9.8l zlib/1.2.3
Host: api.soundcloud.com
Accept: */*
Content-Length: 105
Content-Type: application/x-www-form-urlencoded

Client_id=xxx&Grant_type=authorization_code&Client_secret=yyy&Redirect_uri=appname://oauth-thing&Code=zzz

The only fields that would qualify for case-insensitivity in rfc2616
would be "User-Agent, Host, Accept, Content-Length, Content-Type".

So we're really talking about making the query parameters to the OAuth
handshake case insensitive.

The OAuth2 spec isn't clear on whether or not the keys are expected to
be case-sensitive.

In the OAuth2 spec, there are some expected values that are explicitly
case-sensitive, so it's easy to infer that the keys are also assumed
to be case sensitive as they use the same characters in all examples.
I believe we are doing the right thing by assuming the keys to be
octets instead of character codes, and not accepting "Client_id" in
place of "client_id":
http://tools.ietf.org/html/draft-hammer-oauth2-00 Overall, case
sensitive keys reduces complexity. Imagine how to explain all the
possible expected behaviors in the case of receiving
"Client_id=123&client_id=456".

As Ulrich suggested - the best thing for debugging network clients to
do is crack open HTTP requests with Charles to find the difference
between requests and what is getting put on the wire.
http://www.charlesproxy.com Debugging data is usually gives the
fastest results.

Thanks for you suggestion, but we will stick with treating all
x-www-form-urlencoded keys as case-sensitive.

-Sean

RF

unread,
Feb 14, 2011, 5:03:46 AM2/14/11
to SoundCloudAPI


On Feb 13, 2:02 pm, Sean Treadway <s...@soundcloud.com> wrote:
> Hi RF,
>
> I'll address the subject, as I can't speak to what the Apple libraries
> do to URL data.
>
> It seems there is some confusion between HTTP header fields, and
> application/x-www-form-urlencoded key value pairs.

Yes, I'm definitely confused (I'm not very http savvy). What I've been
talking about all along is HTTP header fields...

> You are correct that the header key value pairs part of an HTTP 1.1
> message (after the request line and before the body) should be handled
> as case-insensitive.  In our servers, we do treat these headers as
> case-insensitive.
>
> The curl example you gave does not add any headers (that's the -H
> parameter),

Oops, ok here's my corrected curl example, without any mixed case
keys:

curl https://api.soundcloud.com/oauth2/token -H 'client_id: xxx' \
-H 'client_secret: yyy'\
-H 'grant_type: authorization_code'\
-H 'redirect_uri: appname://oauth-thing'\
-H 'code: zzz' -d ""

(empty -d to get a POST instead of a GET)

And this doesn't work: {"error":"invalid_client"}, 401 Unauthorized.

I guess my question has become "should this work?".

> So your two requests would look like this:
>
> POST /oauth2/token HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7
> OpenSSL/0.9.8l zlib/1.2.3
> Host: api.soundcloud.com
> Accept: */*
> Content-Length: 105
> Content-Type: application/x-www-form-urlencoded
>
> client_id=xxx&grant_type=authorization_code&client_secret=yyy&redirect_uri= appname://oauth-thing&code=zzz
>
> Compared to:
>
> POST /oauth2/token HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7
> OpenSSL/0.9.8l zlib/1.2.3
> Host: api.soundcloud.com
> Accept: */*
> Content-Length: 105
> Content-Type: application/x-www-form-urlencoded
>
> Client_id=xxx&Grant_type=authorization_code&Client_secret=yyy&Redirect_uri= appname://oauth-thing&Code=zzz
>
> The only fields that would qualify for case-insensitivity in rfc2616
> would be "User-Agent, Host, Accept, Content-Length, Content-Type".
>
> So we're really talking about making the query parameters to the OAuth
> handshake case insensitive.
>
> The OAuth2 spec isn't clear on whether or not the keys are expected to
> be case-sensitive.

If they're plain old vanilla HTTP header fields, then I guess they are
(hence my question above).

> In the OAuth2 spec, there are some expected values that are explicitly
> case-sensitive, so it's easy to infer that the keys are also assumed
> to be case sensitive as they use the same characters in all examples.
> I believe we are doing the right thing by assuming the keys to be
> octets instead of character codes, and not accepting "Client_id" in
> place of "client_id":http://tools.ietf.org/html/draft-hammer-oauth2-00 Overall, case
> sensitive keys reduces complexity.  Imagine how to explain all the
> possible expected behaviors in the case of receiving
> "Client_id=123&client_id=456".

tolower(key) wouldn't work? I'm probably missing something.

> As Ulrich suggested - the best thing for debugging network clients to
> do is crack open HTTP requests with Charles to find the difference
> between requests and what is getting put on the wire.http://www.charlesproxy.com Debugging data is usually gives the
> fastest results.

Nice - I've been using nc -l

> Thanks for you suggestion, but we will stick with treating all
> x-www-form-urlencoded keys as case-sensitive.

I've got nothing to say about x-www-form-urlencoded keys,
I just want to know if you can use HTTP header fields to authenticate
with sound cloud.
If you can then I want to know why my curl example doesn't work (and
then why the Apple equivalent doesn't work).

If you can't use the HTTP header fields, then I've got nothing to say
about anything.

RF.

Sean Treadway

unread,
Feb 14, 2011, 5:41:16 AM2/14/11
to soundc...@googlegroups.com
Hi RF,

On Mon, Feb 14, 2011 at 11:03 AM, RF <rfis...@gmail.com> wrote:
> curl https://api.soundcloud.com/oauth2/token -H 'client_id: xxx' \
>  -H 'client_secret: yyy'\
>  -H 'grant_type: authorization_code'\
>  -H 'redirect_uri: appname://oauth-thing'\
>  -H 'code: zzz' -d ""
>
> (empty -d to get a POST instead of a GET)
>
> And this doesn't work: {"error":"invalid_client"}, 401 Unauthorized.
>
> I guess my question has become "should this work?".

This will unfortunately not work.

When using these fields to authorize, they will need to be
x-www-form-urlencoded in the body or as query parameters in the URI as
described by:

http://tools.ietf.org/html/draft-hammer-oauth2-00#section-3.5.1

The OAuth2 spec does have a section for using HTTP headers for based
authorization:

http://tools.ietf.org/html/draft-hammer-oauth2-00#section-5.1

But this will only look for the authentication fields in the single
"Authorization" HTTP header.

As far as I can tell, there are no provisions in OAuth for getting a
token from passing the client_id and other URI parameters as HTTP
headers.

It sounds like it'd be convenient to treat the HTTP headers as URI
parameters for your tools, but I'm sure there are some other tools
that will help you construct urlencoded query strings too.

Happy hacking and I hope this explanation helps when using the SoundCloud API.

-Sean

RF

unread,
Feb 16, 2011, 4:14:16 PM2/16/11
to SoundCloudAPI


On Feb 14, 11:41 am, Sean Treadway <s...@soundcloud.com> wrote:
> Hi RF,
>
> On Mon, Feb 14, 2011 at 11:03 AM, RF <rfist...@gmail.com> wrote:
> > curlhttps://api.soundcloud.com/oauth2/token-H 'client_id: xxx' \
> >  -H 'client_secret: yyy'\
> >  -H 'grant_type: authorization_code'\
> >  -H 'redirect_uri: appname://oauth-thing'\
> >  -H 'code: zzz' -d ""
>
> > (empty -d to get a POST instead of a GET)
>
> > And this doesn't work: {"error":"invalid_client"}, 401 Unauthorized.
>
> > I guess my question has become "should this work?".
>
> This will unfortunately not work.
>
> When using these fields to authorize, they will need to be
> x-www-form-urlencoded in the body or as query parameters in the URI as
> described by:
>
> http://tools.ietf.org/html/draft-hammer-oauth2-00#section-3.5.1

I see.

> The OAuth2 spec does have a section for using HTTP headers for based
> authorization:
>
> http://tools.ietf.org/html/draft-hammer-oauth2-00#section-5.1
>
> But this will only look for the authentication fields in the single
> "Authorization" HTTP header.

Ah.

> As far as I can tell, there are no provisions in OAuth for getting a
> token from passing the client_id and other URI parameters as HTTP
> headers.
>
> It sounds like it'd be convenient to treat the HTTP headers as URI
> parameters for your tools, but I'm sure there are some other tools
> that will help you construct urlencoded query strings too.

It's no big deal - I was just under the mistaken impression that
arguments passed as
a) part of the URL, b) as HTTP header fields and c) as form data were
all equivalent
and so it seemed wrong that b) should not work.

Thanks!
RF.
Reply all
Reply to author
Forward
0 new messages