1/* 2 HTTP-redirect support 3 Copyright (C) 1999-2007, Joe Orton <joe@manyfish.co.uk> 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Library General Public 7 License as published by the Free Software Foundation; either 8 version 2 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Library General Public License for more details. 14 15 You should have received a copy of the GNU Library General Public 16 License along with this library; if not, write to the Free 17 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 18 MA 02111-1307, USA 19 20*/ 21 22#include "config.h" 23 24#ifdef HAVE_STDLIB_H 25#include <stdlib.h> 26#endif 27#ifdef HAVE_STRING_H 28#include <string.h> 29#endif 30 31#include "ne_session.h" 32#include "ne_request.h" 33#include "ne_alloc.h" 34#include "ne_uri.h" 35#include "ne_redirect.h" 36#include "ne_internal.h" 37#include "ne_string.h" 38 39#define REDIRECT_ID "http://www.webdav.org/neon/hooks/http-redirect" 40 41struct redirect { 42 char *requri; 43 int valid; /* non-zero if .uri contains a redirect */ 44 ne_uri uri; 45 ne_session *sess; 46}; 47 48static void 49create(ne_request *req, void *session, const char *method, const char *uri) 50{ 51 struct redirect *red = session; 52 if (red->requri) ne_free(red->requri); 53 red->requri = ne_strdup(uri); 54} 55 56#define REDIR(n) ((n) == 301 || (n) == 302 || (n) == 303 || \ 57 (n) == 307) 58 59static int post_send(ne_request *req, void *private, const ne_status *status) 60{ 61 struct redirect *red = private; 62 const char *location = ne_get_response_header(req, "Location"); 63 ne_buffer *path = NULL; 64 int ret; 65 66 /* Don't do anything for non-redirect status or no Location header. */ 67 if (!REDIR(status->code) || location == NULL) 68 return NE_OK; 69 70 if (strstr(location, "://") == NULL && location[0] != '/') { 71 char *pnt; 72 73 path = ne_buffer_create(); 74 ne_buffer_zappend(path, red->requri); 75 pnt = strrchr(path->data, '/'); 76 77 if (pnt && pnt[1] != '\0') { 78 /* Chop off last path segment. */ 79 pnt[1] = '\0'; 80 ne_buffer_altered(path); 81 } 82 ne_buffer_zappend(path, location); 83 location = path->data; 84 } 85 86 /* free last uri. */ 87 ne_uri_free(&red->uri); 88 89 /* Parse the Location header */ 90 if (ne_uri_parse(location, &red->uri) || red->uri.path == NULL) { 91 red->valid = 0; 92 ne_set_error(red->sess, _("Could not parse redirect destination URL")); 93 ret = NE_ERROR; 94 } else { 95 /* got a valid redirect. */ 96 red->valid = 1; 97 ret = NE_REDIRECT; 98 99 if (!red->uri.host) { 100 /* Not an absoluteURI: breaks 2616 but everybody does it. */ 101 ne_fill_server_uri(red->sess, &red->uri); 102 } 103 } 104 105 if (path) ne_buffer_destroy(path); 106 107 return ret; 108} 109 110static void free_redirect(void *cookie) 111{ 112 struct redirect *red = cookie; 113 ne_uri_free(&red->uri); 114 if (red->requri) 115 ne_free(red->requri); 116 ne_free(red); 117} 118 119void ne_redirect_register(ne_session *sess) 120{ 121 struct redirect *red = ne_calloc(sizeof *red); 122 123 red->sess = sess; 124 125 ne_hook_create_request(sess, create, red); 126 ne_hook_post_send(sess, post_send, red); 127 ne_hook_destroy_session(sess, free_redirect, red); 128 129 ne_set_session_private(sess, REDIRECT_ID, red); 130} 131 132const ne_uri *ne_redirect_location(ne_session *sess) 133{ 134 struct redirect *red = ne_get_session_private(sess, REDIRECT_ID); 135 136 if (red && red->valid) 137 return &red->uri; 138 else 139 return NULL; 140} 141 142