From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Lars Ingebrigtsen Newsgroups: gmane.emacs.devel Subject: with-url Date: Thu, 29 Dec 2016 01:41:02 +0100 Organization: Programmerer Ingebrigtsen Message-ID: <87mvffva75.fsf@gnus.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1482972123 16171 195.159.176.226 (29 Dec 2016 00:42:03 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Thu, 29 Dec 2016 00:42:03 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Dec 29 01:41:59 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cMOn8-0003TC-JM for ged-emacs-devel@m.gmane.org; Thu, 29 Dec 2016 01:41:58 +0100 Original-Received: from localhost ([::1]:33212 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cMOnB-0008Ap-LO for ged-emacs-devel@m.gmane.org; Wed, 28 Dec 2016 19:42:01 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:33023) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cMOmc-00086h-LK for emacs-devel@gnu.org; Wed, 28 Dec 2016 19:41:28 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cMOmY-0001pT-FF for emacs-devel@gnu.org; Wed, 28 Dec 2016 19:41:26 -0500 Original-Received: from [195.159.176.226] (port=56272 helo=blaine.gmane.org) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cMOmY-0001oR-8c for emacs-devel@gnu.org; Wed, 28 Dec 2016 19:41:22 -0500 Original-Received: from list by blaine.gmane.org with local (Exim 4.84_2) (envelope-from ) id 1cMOmO-0006VD-RN for emacs-devel@gnu.org; Thu, 29 Dec 2016 01:41:12 +0100 X-Injected-Via-Gmane: http://gmane.org/ Mail-Followup-To: emacs-devel@gnu.org Original-Lines: 179 Original-X-Complaints-To: usenet@blaine.gmane.org Mail-Copies-To: never Cancel-Lock: sha1:O52en9FbW/WVq8S9rOoHKJyGPck= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 195.159.176.226 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:210933 Archived-At: I've basically implemented the previously discussed `with-url' macro. Doc string below. I'll push it to a feature branch tomorrow. But I have some style questions I'm not quite sure about what the right approach is. First of all, the basic form looks like this: (with-url (headers "http://fsf.org/") (message "The size of the FSF front page is %s" (buffer-size))) And you can cram all the parameters as keywords after the URL. For instance, if you put :method "POST" in there, it'll use POST instead of GET, and if you put :wait t in there, everything will be done synchronously instead of asynchronously. (Which is often nice when testing code.) First question: Should the `headers' variable binding be explicit or implicit? In Common Lisp there's a culture for having them all be very explicit, but in Emacs we have a culture for hiding variables in buffer-local variables. One is nice and readable, and the other is nice and short. (with-url (headers "http://fsf.org/") (message "Content type is %s" (url-header headers 'content-type))) ==> Content type is text/html;charset=utf-8 vs (with-url ("http://fsf.org/") (message "Content type is %s" (url-header 'content-type))) The latter looks nicer, no? The problem with that is this: (with-url ("http://fsf.org/") (with-url ("http://goole.org/") (message "Content type is %s" (url-header 'content-type)))) But I wanted the first one! (with-url ("http://fsf.org/") (let ((buffer (current-buffer))) (with-url ("http://goole.org/") (message "Content type is %s" (with-current-buffer buffer (url-header 'content-type)))))) *waugh* And, yes, working with URL-ey stuff, you're often nesting these calls, because the first call gives you some information, and then you want to do another request... But do you often refer back to the headers of the previous request? I don't know? Opinions? The second question is about error handling. URL requests will fail, either because the page doesn't exist, or the host is down, or it times out. (Yes, there are timeouts in the new interface.) So in real life, these calls should always look like... (with-url (headers "http://fsf.org/") (if (url-header-ok-p headers) (message "Content type is %s" (url-header headers 'content-type) (message "I guess I'll do something else")))) Although looking at `url-retrieve' calls in the Emacs code base, many callers don't bother because error handling is boring. And, besides, it'll indent the code so much. :-) An alternative would be to say something like... er... (with-url (headers "http://fsf.org/") (ok (message "Content type is %s" (url-header headers 'content-type))) (error (message "I guess I'll do something else"))) That is, make the with-url have two body forms -- one which is called when things went OK, and one when it didn't. (And marked by those two symbols.) If the body doesn't have those symbols, then it's all an `ok' form and no error callbacks. Or (with-url (headers "http://fsf.org/") (error (message "I guess I'll do something else")) (message "Content type is %s" (url-header headers 'content-type))) That is, you can put the error handling form at the start if the first symbol is `error' in that form. Well, it can't be `error', but perhaps `url-error'. Or... Opinions? :-) ---- with-url is a Lisp macro in ‘../../with-url/lisp/url/with-url.el’. (with-url (HEADER-VARIABLE URL &key WAIT TIMEOUT READ-TIMEOUT SILENT INHIBIT-COOKIES INHIBIT-CACHE HEADERS (METHOD "GET") DATA (DATA-CHARSET 'utf-8) DATA-ENCODING) &body BODY) Retrieve URL and execute BODY with point in a buffer with the response. Example: (with-url (headers "http://fsf.org/") (message "The size of the FSF front page is %s" (buffer-size))) The buffer is killed after BODY has exited. HEADER-VARIABLE is bound to a structure that contains the response headers and status. These can be accessed with ‘url-header’ like this: (url-header headers "Content-Type") Case is not significant. Additional keywords can be given to ‘with-url’ to alter its operation. :wait t Normal ‘with-url’ operation is asynchronous. If this parameter is given, the retrieval will be synchronous instead. :timeout SECONDS Give up after approximately SECONDS seconds and execute BODY. :read-timeout SECONDS If no data has been received for the last SECONDS seconds, give up and execute BODY. :silent t Issue no messages during operation. :inhibit-cookies t Neither send nor store cookies. :headers ALIST Add ALIST to the headers sent over to the server. This should typically look like (("User-Agent" "Emacs")) If the header name is the same as one of the automatically generated headers, the value from this list will override the automatically generated header. To disable the header completely, use nil as the value. Additional elements in this alist are interpreted as the charset (defaulting to utf-8) and the encoding method (defaulting to url-encode). :method GET/POST/etc The method to use for retrieving an HTTP(S) resource. This defaults to GET, and other popular values are POST, UPDATE and PUT. :data STRING Data to include in the body of the HTTP(S) request when using POST, UPDATE or PUT. :data-charset CHARSET What charset this data should be interpreted as. This defaults to UTF-8. :data-encoding ENCODING When using the posting methods, the data is usually encoded in some fashion. Popular encodings are ‘url-form’ and ‘base64’. [back] -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no