I want to use http-client to make an HTTP request equivalent to:
curl -u 'user:pass' 'https://api.example.net/a/b/c'
I have read the docs for http-client, as well as for intarweb and uri-common, but I am still unsure of how to achieve this.
I can see that it's possible to set a username and password with make-uri, but I'm not sure if that's the best option.
I'm open to multiple solutions if there is more than one way to do it, but an idiomatic answer is preferable.
As the docs say,
the default value is a procedure which extracts the username and password components from the URI"
So, setting the password with make-uri is definitely supported and probably the simplest way in general. This is why with-input-from-request and friends accept either a string, an URI object or a request - you pass in the simplest thing that can work.
(define user "user")
(define pass "pass")
(determine-username/password
(lambda (uri realm)
(values user pass)))
See https://wiki.call-cc.org/eggref/5/http-client#authentication-support for the technical details.
Related
I am learning TCL for my work and I have a question that I can not find the answer.
It concerns the usage of ::http::geturl token.
Let's consider the following code:
package require http
set url "some url"
set token [::http::geturl $url]
# the question is about the line below
upvar #0 $token state
set data $state(body)
If I'm not doing a mistake, the use of upvar here is just creating an alias state referring to token.
I am wondering why is this line always written in any code I can see (even in the TCL documentation)?
To be more clear, is set data $state(body) equivalent to set data $token(body)?
And if it is the case, why do we write this upvar if it is not necessary (and not really useful but making the script heavier)?
On my laptop, I cannot install anything such as tclsh for now, so I could not perform the test to find the answer by myself.
This is why I require your help.
Thanks to anyone who will answer me.
token actually contains a string, something like ::http::1 (the number increments the more calls you make to ::http::geturl), and that string is the name of an array.
So when you do $token(body), you are telling the code to find the value for the key body in the array token, except that this array doesn't exist. The array's actual name is ::http::1 as mentioned earlier. So it's easier to create an alias than to use something like, say, lindex [array get $token body] 1.
When calling loginWithPassword I receive an error with code 403 in both cases: when the user doesn't exist and when the password is wrong. I know that theirs messages/reasons are different, but I think that comparing with string is not a good practice. Is there a different way of differentiating these cases?
UPDATE Using accounts-password
No real way of differentiating other than checking the error description string (that is what it is for).
You can always implement your own mechanism server-side (e.g, a method), but the default one sends a numeric error code (normally corresponding to the HTTP code - in this case, 403 forbidden), accompanied by a string.
They have not changed recently and it is fairly safe to depend on them, especially if it is not something mission-critical.
You could implement a method that checks for the existence of a user and then call that after a failed login attempt. If the user exists then you can display a bad password warning.
You could even check existence before the password is typed and put a green checkmark next to the username field if the user is found or a red X otherwise.
There are many ways to do this.
I'm using vert.x to write an application. It doesn't have built-in cookie support yet, and we have to use "putHeader()" method to manually set cookies.
Now I want to set several cookies, so I write:
req.response.putHeader("Set-Cookie", "aaa=111; path=/")
req.response.putHeader("Set-Cookie", "bbb=222; path=/")
req.response.putHeader("Set-Cookie", "ccc=333; path=/")
But I found vert.x send only one "Set-Cookie":
Set-Cookie ccc=333; path=/
I'm not sure if I misunderstand something. Can server send multi "Set-Cookie" commands one time? Is it correct to send multi cookies this way?
Use netty's io.netty.handler.codec.http.ServerCookieEncoder functionality:
req.response.putHeader("Set-Cookie",
ServerCookieEncoder.encode(new DefaultCookie("aaa", "111")))
there're many useful method signatures:
ServerCookieEncoder.encode(Cookie cookie)
ServerCookieEncoder.encode(Cookie... cookies)
ServerCookieEncoder.encode(Collection<Cookie> cookies)
ServerCookieEncoder.encode(Iterable<Cookie> cookies)
I think no, it's impossible out of the box because headers stored in a HashMap:
https://github.com/purplefox/vert.x/blob/master/src/main/java/org/vertx/java/core/http/impl/DefaultHttpServerResponse.java#L81
You can:
Open new issue
Comment existing issue https://github.com/purplefox/vert.x/issues/89
Checkout source and use map what allow duplicate keys
Map implementation with duplicate keys (you need handle duplicate manually, for instance Location-header should be only one time
Extend DefaultHttpServerResponse and see how you can integrate it
Merge cookies and handle it manually, for instance:
req.response.putHeader("Set-Cookie", "aaa=111&bbb=222&ccc=333; path=/")
There is one work-arround.
req.response()
.putHeader("Set-Cookie", "some=cookie;max-age=1000;path=/;HttpOnly"
+"\nSet-Cookie: next=cookie"
+"\nSet-Cookie: nnext=cookie;HttpOnly");
I was wondering if it's acceptable to put custom data in an HTTP authorization header. We're designing a RESTful API and we may need a way to specify a custom method of authorization. As an example, let's call it FIRE-TOKEN authentication.
Would something like this be valid and allowed according to the spec: Authorization: FIRE-TOKEN 0PN5J17HBGZHT7JJ3X82:frJIUN8DYpKDtOLCwo//yllqDzg=
The first part of the second string (before the ':') is the API key, the second part is a hash of query string.
The format defined in RFC2617 is credentials = auth-scheme #auth-param. So, in agreeing with fumanchu, I think the corrected authorization scheme would look like
Authorization: FIRE-TOKEN apikey="0PN5J17HBGZHT7JJ3X82", hash="frJIUN8DYpKDtOLCwo//yllqDzg="
Where FIRE-TOKEN is the scheme and the two key-value pairs are the auth parameters. Though I believe the quotes are optional (from Apendix B of p7-auth-19)...
auth-param = token BWS "=" BWS ( token / quoted-string )
I believe this fits the latest standards, is already in use (see below), and provides a key-value format for simple extension (if you need additional parameters).
Some examples of this auth-param syntax can be seen here...
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p7-auth-19#section-4.4
https://developers.google.com/youtube/2.0/developers_guide_protocol_clientlogin
https://developers.google.com/accounts/docs/AuthSub#WorkingAuthSub
Put it in a separate, custom header.
Overloading the standard HTTP headers is probably going to cause more confusion than it's worth, and will violate the principle of least surprise. It might also lead to interoperability problems for your API client programmers who want to use off-the-shelf tool kits that can only deal with the standard form of typical HTTP headers (such as Authorization).
No, that is not a valid production according to the "credentials" definition in RFC 2617. You give a valid auth-scheme, but auth-param values must be of the form token "=" ( token | quoted-string ) (see section 1.2), and your example doesn't use "=" that way.
Old question I know, but for the curious:
Believe it or not, this issue was solved ~2 decades ago with HTTP BASIC, which passes the value as base64 encoded username:password. (See http://en.wikipedia.org/wiki/Basic_access_authentication#Client_side)
You could do the same, so that the example above would become:
Authorization: FIRE-TOKEN MFBONUoxN0hCR1pIVDdKSjNYODI6ZnJKSVVOOERZcEtEdE9MQ3dvLy95bGxxRHpnPQ==
I need to invoke a process which doesn't require any input from the user, just a trigger. I plan to use POST /uri without a body to trigger the process. I want to know if this is considered bad from both HTTP and REST perspectives?
I asked this question on the IETF HTTP working group a few months ago. The short answer is: NO, it's not a bad practice (but I suggest reading the thread for more details).
Using a POST instead of a GET is perfectly reasonable, since it also instructs the server (and gateways along the way) not to return a cached response.
POST is completely OK. In difference of GET with POST you are changing the state of the system (most likely your trigger is "doing" something and changing data).
I used POST already without payload and it "feels" OK. One thing you should do when using POST without payload: Pass header Content-Length: 0. I remember problems with some proxies when I api-client didn't pass it.
If you use POST /uri without a body it is something like using a function which does not take an argument .e.g int post (void); so it is reasonable to have function to your resource class which can change the state of an object without having an argument. If you consider to implement the Unix touch function for a URI, is not it be good choice?
Yes, it's OK to send a POST request without a body and instead use query string parameters. But be careful if your parameters contain characters that are not HTTP valid you will have to encode them.
For example if you need to POST 'hello world' to and end point you would have to make it look like this: http://api.com?param=hello%20world
Support for the answers that POST is OK in this case is that in Python's case, the OpenAPI framework "FastAPI" generates a Swagger GUI (see image) that doesn't contain a Body section when a method (see example below) doesn't have a parameter to accept a body.
the method "post_disable_db" just accepts a path parameter "db_name" and doesn't have a 2nd parameter which would imply a mandatory body.
#router.post('/{db_name}/disable',
status_code=HTTP_200_OK,
response_model=ResponseSuccess,
summary='',
description=''
)
async def post_disable_db(db_name: str):
try:
response: ResponseSuccess = Handlers.databases_handler.post_change_db_enabled_state(db_name, False)
except HTTPException as e:
raise (e)
except Exception as e:
logger.exception(f'Changing state of DB to enabled=False failed due to: {e.__repr__()}')
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, detail=e.__repr__())
return response