Start work on Torus extension for virt_db
[metaproxy-moved-to-github.git] / src / torus.cpp
1 /* This file is part of Metaproxy.
2    Copyright (C) 2005-2011 Index Data
3
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include <metaproxy/xmlutil.hpp>
20
21 #include <string.h>
22 #include <yaz/wrbuf.h>
23 #include <yaz/zgdu.h>
24 #include <yaz/srw.h>
25 #include <yaz/comstack.h>
26
27 #include "torus.hpp"
28
29 namespace mp = metaproxy_1;
30
31
32 static Z_GDU *get_HTTP_Request_url(ODR odr, const char *url)
33 {
34     Z_GDU *p = z_get_HTTP_Request(odr);
35     const char *host = url;
36     const char *cp0 = strstr(host, "://");
37     const char *cp1 = 0;
38     if (cp0)
39         cp0 = cp0+3;
40     else
41         cp0 = host;
42     
43     cp1 = strchr(cp0, '/');
44     if (!cp1)
45         cp1 = cp0 + strlen(cp0);
46     
47     if (cp0 && cp1)
48     {
49         char *h = (char*) odr_malloc(odr, cp1 - cp0 + 1);
50         memcpy (h, cp0, cp1 - cp0);
51         h[cp1-cp0] = '\0';
52         z_HTTP_header_add(odr, &p->u.HTTP_Request->headers, "Host", h);
53     }
54     p->u.HTTP_Request->path = odr_strdup(odr, *cp1 ? cp1 : "/");
55     return p;
56 }
57
58 static WRBUF get_url(const char *uri, WRBUF username, WRBUF password,
59                      int *code)
60 {
61     int number_of_redirects = 0;
62     WRBUF result = 0;
63     ODR out = odr_createmem(ODR_ENCODE);
64     ODR in = odr_createmem(ODR_DECODE);
65
66     while (1)
67     {
68         Z_HTTP_Response *res = 0;
69         const char *location = 0;
70         Z_GDU *gdu = get_HTTP_Request_url(out, uri);
71         yaz_log(YLOG_LOG, "GET %s", uri);
72         gdu->u.HTTP_Request->method = odr_strdup(out, "GET");
73         if (username && password)
74         {
75             z_HTTP_header_add_basic_auth(out, &gdu->u.HTTP_Request->headers,
76                                          wrbuf_cstr(username),
77                                          wrbuf_cstr(password));
78         }
79         z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers, "Accept",
80                           "application/xml");
81         if (!z_GDU(out, &gdu, 0, 0))
82         {
83             yaz_log(YLOG_WARN, "Can not encode HTTP request URL:%s", uri);        
84             break;
85         }
86         void *add;
87         COMSTACK conn = cs_create_host(uri, 1, &add);
88         if (!conn)
89             yaz_log(YLOG_WARN, "Bad address for URL:%s", uri);
90         else if (cs_connect(conn, add) < 0)
91             yaz_log(YLOG_WARN, "Can not connect to URL:%s", uri);
92         else
93         {
94             int len;
95             char *buf = odr_getbuf(out, &len, 0);
96             
97             if (cs_put(conn, buf, len) < 0)
98                 yaz_log(YLOG_WARN, "cs_put failed URL:%s", uri);
99             else
100             {
101                 char *netbuffer = 0;
102                 int netlen = 0;
103                 int cs_res = cs_get(conn, &netbuffer, &netlen);
104                 if (cs_res <= 0)
105                 {
106                     yaz_log(YLOG_WARN, "cs_get failed URL:%s", uri);
107                 }
108                 else
109                 {
110                     Z_GDU *gdu;
111                     odr_setbuf(in, netbuffer, cs_res, 0);
112                     if (!z_GDU(in, &gdu, 0, 0)
113                         || gdu->which != Z_GDU_HTTP_Response)
114                     {
115                         yaz_log(YLOG_WARN, "HTTP decoding failed "
116                                 "URL:%s", uri);
117                     }
118                     else
119                     {
120                         res = gdu->u.HTTP_Response;
121                     }
122                 }
123                 xfree(netbuffer);
124             }
125             cs_close(conn);
126         }
127         if (!res)
128             break; // ERROR
129         *code = res->code;
130         location = z_HTTP_header_lookup(res->headers, "Location");
131         if (++number_of_redirects < 10 &&
132             location && (*code == 301 || *code == 302 || *code == 307))
133         {
134             odr_reset(out);
135             uri = odr_strdup(out, location);
136             odr_reset(in);
137         }
138         else
139         {
140             result = wrbuf_alloc();
141             wrbuf_write(result, res->content_buf, res->content_len);
142             break;
143         }
144     }
145     odr_destroy(out);
146     odr_destroy(in);
147     return result;
148 }
149
150
151 mp::Torus::Torus()
152 {
153     doc = 0;
154 }
155
156 mp::Torus::~Torus()
157 {
158     if (doc)
159         xmlFreeDoc(doc);
160 }
161
162 void mp::Torus::read_searchables(std::string url)
163 {
164     if (url.length() == 0)
165         return;
166
167     if (doc)
168     {
169         xmlFreeDoc(doc);
170         doc = 0;
171     }
172        
173     int code;
174     WRBUF w = get_url(url.c_str(), 0, 0, &code);
175     if (code == 200)
176     {
177         doc = xmlParseMemory(wrbuf_buf(w), wrbuf_len(w));
178         if (doc)
179             yaz_log(YLOG_LOG, "xmlParseMemory OK");
180     }
181     wrbuf_destroy(w);
182 }
183
184 /*
185  * Local variables:
186  * c-basic-offset: 4
187  * c-file-style: "Stroustrup"
188  * indent-tabs-mode: nil
189  * End:
190  * vim: shiftwidth=4 tabstop=8 expandtab
191  */
192