Back to index

avfs  1.0.1
dav_207.c
Go to the documentation of this file.
00001 /* 
00002    WebDAV 207 multi-status response handling
00003    Copyright (C) 1999-2001, Joe Orton <joe@light.plus.com>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009    
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00018    MA 02111-1307, USA
00019 
00020 */
00021 
00022 /* Generic handling for WebDAV 207 Multi-Status responses. */
00023 
00024 #include "config.h"
00025 
00026 #ifdef HAVE_STDLIB_H
00027 #include <stdlib.h>
00028 #endif
00029 
00030 #include "http_utils.h"
00031 #include "hip_xml.h"
00032 #include "dav_207.h"
00033 #include "uri.h"
00034 #include "ne_alloc.h"
00035 
00036 #include "neon_i18n.h"
00037 
00038 struct dav_207_parser_s {
00039     dav_207_start_response start_response;
00040     dav_207_end_response end_response;
00041     dav_207_start_propstat start_propstat;
00042     dav_207_end_propstat end_propstat;
00043     hip_xml_parser *parser;
00044     void *userdata;
00045     /* current position */
00046     void *response, *propstat;
00047     /* caching */
00048     http_status status;
00049     char *description, *href, *status_line;
00050 };
00051 
00052 const static struct hip_xml_elm elements[] = {
00053     { "DAV:", "multistatus", DAV_ELM_multistatus, 0 },
00054     { "DAV:", "response", DAV_ELM_response, 0 },
00055     { "DAV:", "responsedescription", DAV_ELM_responsedescription, 
00056       HIP_XML_CDATA },
00057     { "DAV:", "href", DAV_ELM_href, HIP_XML_CDATA },
00058     { "DAV:", "propstat", DAV_ELM_propstat, 0 },
00059     { "DAV:", "prop", DAV_ELM_prop, 0 },
00060     { "DAV:", "status", DAV_ELM_status, HIP_XML_CDATA },
00061     { NULL }
00062 };
00063 
00064 /* Set the callbacks for the parser */
00065 void dav_207_set_response_handlers(dav_207_parser *p,
00066                                dav_207_start_response start,
00067                                dav_207_end_response end)
00068 {
00069     p->start_response = start;
00070     p->end_response = end;
00071 }
00072 
00073 void dav_207_set_propstat_handlers(dav_207_parser *p,
00074                                dav_207_start_propstat start,
00075                                dav_207_end_propstat end)
00076 {
00077     p->start_propstat = start;
00078     p->end_propstat = end;
00079 }
00080 
00081 void *dav_207_get_current_response(dav_207_parser *p)
00082 {
00083     return p->response;
00084 }
00085 
00086 void *dav_207_get_current_propstat(dav_207_parser *p)
00087 {
00088     return p->propstat;
00089 }
00090 
00091 static int 
00092 start_element(void *userdata, const struct hip_xml_elm *elm, 
00093              const char **atts) 
00094 {
00095     dav_207_parser *p = userdata;
00096     
00097     switch (elm->id) {
00098     case DAV_ELM_response:
00099        /* Create new response delayed until we get HREF */
00100        break;
00101     case DAV_ELM_propstat:
00102        if (p->start_propstat) {
00103            p->propstat = (*p->start_propstat)(p->userdata, p->response);
00104        }
00105        break;
00106     }
00107     return 0;
00108 }
00109 
00110 static int 
00111 end_element(void *userdata, const struct hip_xml_elm *elm, const char *cdata)
00112 {
00113     dav_207_parser *p = userdata;
00114 
00115     switch (elm->id) {
00116     case DAV_ELM_responsedescription:
00117        if (cdata != NULL) {
00118            HTTP_FREE(p->description);
00119            p->description = ne_strdup(cdata);
00120        }
00121        break;
00122     case DAV_ELM_href:
00123        /* Now we have the href, begin the response */
00124        if (p->start_response && cdata != NULL) {
00125            p->response = (*p->start_response)(p->userdata, cdata);
00126        }
00127        break;
00128     case DAV_ELM_status:
00129        if (cdata) {
00130            HTTP_FREE(p->status_line);
00131            p->status_line = ne_strdup(cdata);
00132            if (http_parse_statusline(p->status_line, &p->status)) {
00133               char buf[500];
00134               DEBUG(DEBUG_HTTP, "Status line: %s\n", cdata);
00135               snprintf(buf, 500, 
00136                       _("Invalid HTTP status line in status element at line %d of response:\nStatus line was: %s"),
00137                       hip_xml_currentline(p->parser), p->status_line);
00138               hip_xml_set_error(p->parser, buf);
00139               HTTP_FREE(p->status_line);
00140               return -1;
00141            } else {
00142               DEBUG(DEBUG_XML, "Decoded status line: %s\n", p->status_line);
00143            }
00144        }
00145        break;
00146     case DAV_ELM_propstat:
00147        if (p->end_propstat) {
00148            (*p->end_propstat)(p->userdata, p->propstat, p->status_line,
00149                             p->status_line?&p->status:NULL, p->description);
00150        }
00151        p->propstat = NULL;
00152        HTTP_FREE(p->description);
00153        HTTP_FREE(p->status_line);
00154        break;
00155     case DAV_ELM_response:
00156        if (p->end_response) {
00157            (*p->end_response)(p->userdata, p->response, p->status_line,
00158                             p->status_line?&p->status:NULL, p->description);
00159        }
00160        p->response = NULL;
00161        HTTP_FREE(p->status_line);
00162        HTTP_FREE(p->description);
00163        break;
00164     }
00165     return 0;
00166 }
00167 
00168 /* This should map directly from the DTD... with the addition of
00169  * ignoring anything we don't understand, being liberal in what we
00170  * accept. */
00171 static int check_context(hip_xml_elmid parent, hip_xml_elmid child) 
00172 {
00173     DEBUG(DEBUG_XML, "207cc: %d in %d\n", child, parent);
00174     switch (parent) {
00175     case HIP_ELM_root:
00176        switch (child) {
00177        case DAV_ELM_multistatus:
00178        case DAV_ELM_response: /* not sure why this is here... */
00179            return HIP_XML_VALID;
00180        default:
00181            break;
00182        }
00183        break;
00184     case DAV_ELM_multistatus:
00185        /* <!ELEMENT multistatus (response+, responsedescription?) > */
00186        switch (child) {
00187        case DAV_ELM_response:
00188        case DAV_ELM_responsedescription:
00189            return HIP_XML_VALID;
00190        default:
00191            break;
00192        }
00193        break;
00194     case DAV_ELM_response:
00195        /* <!ELEMENT response (href, ((href*, status)|(propstat+)),
00196           responsedescription?) > */
00197        switch (child) {
00198        case DAV_ELM_href:
00199        case DAV_ELM_status:
00200        case DAV_ELM_propstat:
00201        case DAV_ELM_responsedescription:
00202            return HIP_XML_VALID;
00203        default:
00204            break;
00205        }
00206        break;
00207     case DAV_ELM_propstat:
00208        /* <!ELEMENT propstat (prop, status, responsedescription?) > */
00209        switch (child) {
00210        case DAV_ELM_prop: 
00211        case DAV_ELM_status:
00212        case DAV_ELM_responsedescription:
00213            return HIP_XML_VALID;
00214        default:
00215            break;
00216        }
00217        break;
00218     default:
00219        break;
00220     }
00221 
00222     return HIP_XML_DECLINE;
00223 }
00224 
00225 static int ignore_cc(hip_xml_elmid parent, hip_xml_elmid child) 
00226 {
00227     if (child == HIP_ELM_unknown || parent == HIP_ELM_unknown) {
00228        DEBUG(DEBUG_XML, "207 catch-all caught %d in %d\n", child, parent);
00229        return HIP_XML_VALID;
00230     }
00231 
00232     return HIP_XML_DECLINE;
00233 }
00234 
00235 void dav_207_ignore_unknown(dav_207_parser *p)
00236 {
00237     static const struct hip_xml_elm any_elms[] = {
00238        { "", "", HIP_ELM_unknown, HIP_XML_COLLECT },
00239        { NULL }
00240     };
00241     
00242     hip_xml_push_handler(p->parser, any_elms,
00243                       ignore_cc, NULL, NULL, NULL);
00244     
00245 }
00246 
00247 dav_207_parser *dav_207_create(hip_xml_parser *parser, void *userdata)
00248 {
00249     dav_207_parser *p = ne_calloc(sizeof *p);
00250 
00251     p->parser = parser;
00252     p->userdata = userdata;
00253     
00254     /* Add handler for the standard 207 elements */
00255     hip_xml_push_handler(parser, elements, check_context, 
00256                       start_element, end_element, p);
00257     
00258     return p;
00259 }
00260 
00261 void dav_207_destroy(dav_207_parser *p) 
00262 {
00263     free(p);
00264 }
00265 
00266 int dav_accept_207(void *userdata, http_req *req, http_status *status)
00267 {
00268     return (status->code == 207);
00269 }