1 : /******************************************************************************
2 : * $Id: wcsdataset.cpp 10645 2007-01-18 02:22:39Z warmerdam $
3 : *
4 : * Project: WCS Client Driver
5 : * Purpose: Implementation of an HTTP fetching driver.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_pam.h"
31 : #include "cpl_string.h"
32 : #include "cpl_http.h"
33 : #include "cpl_atomic_ops.h"
34 :
35 : CPL_CVSID("$Id: wcsdataset.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
36 :
37 :
38 : /************************************************************************/
39 : /* HTTPFetchContentDispositionFilename() */
40 : /************************************************************************/
41 :
42 2 : static const char* HTTPFetchContentDispositionFilename(char** papszHeaders)
43 : {
44 2 : char** papszIter = papszHeaders;
45 19 : while(papszIter && *papszIter)
46 : {
47 : /* For multipart, we have in raw format, but without end-of-line characters */
48 15 : if (strncmp(*papszIter, "Content-Disposition: attachment; filename=", 42) == 0)
49 : {
50 0 : return *papszIter + 42;
51 : }
52 : /* For single part, the headers are in KEY=VAL format, but with e-o-l ... */
53 15 : else if (strncmp(*papszIter, "Content-Disposition=attachment; filename=", 41) == 0)
54 : {
55 0 : char* pszVal = (char*)(*papszIter + 41);
56 0 : char* pszEOL = strchr(pszVal, '\r');
57 0 : if (pszEOL) *pszEOL = 0;
58 0 : pszEOL = strchr(pszVal, '\n');
59 0 : if (pszEOL) *pszEOL = 0;
60 0 : return pszVal;
61 : }
62 15 : papszIter ++;
63 : }
64 2 : return NULL;
65 : }
66 :
67 : /************************************************************************/
68 : /* HTTPOpen() */
69 : /************************************************************************/
70 :
71 10722 : static GDALDataset *HTTPOpen( GDALOpenInfo * poOpenInfo )
72 :
73 : {
74 : static volatile int nCounter = 0;
75 :
76 10722 : if( poOpenInfo->nHeaderBytes != 0 )
77 358 : return NULL;
78 :
79 10364 : if( !EQUALN(poOpenInfo->pszFilename,"http:",5)
80 : && !EQUALN(poOpenInfo->pszFilename,"https:",6)
81 : && !EQUALN(poOpenInfo->pszFilename,"ftp:",4) )
82 10362 : return NULL;
83 :
84 : /* -------------------------------------------------------------------- */
85 : /* Fetch the result. */
86 : /* -------------------------------------------------------------------- */
87 2 : CPLErrorReset();
88 :
89 2 : CPLHTTPResult *psResult = CPLHTTPFetch( poOpenInfo->pszFilename, NULL );
90 :
91 : /* -------------------------------------------------------------------- */
92 : /* Try to handle errors. */
93 : /* -------------------------------------------------------------------- */
94 2 : if( psResult == NULL || psResult->nDataLen == 0
95 : || CPLGetLastErrorNo() != 0 )
96 : {
97 0 : CPLHTTPDestroyResult( psResult );
98 0 : return NULL;
99 : }
100 :
101 : /* -------------------------------------------------------------------- */
102 : /* Create a memory file from the result. */
103 : /* -------------------------------------------------------------------- */
104 2 : CPLString osResultFilename;
105 :
106 2 : int nNewCounter = CPLAtomicInc(&nCounter);
107 :
108 2 : const char* pszFilename = HTTPFetchContentDispositionFilename(psResult->papszHeaders);
109 2 : if (pszFilename == NULL)
110 : {
111 2 : pszFilename = CPLGetFilename(poOpenInfo->pszFilename);
112 : /* If we have special characters, let's default to a fixed name */
113 2 : if (strchr(pszFilename, '?') || strchr(pszFilename, '&'))
114 0 : pszFilename = "file.dat";
115 : }
116 :
117 : osResultFilename.Printf( "/vsimem/http_%d/%s",
118 2 : nNewCounter, pszFilename );
119 :
120 : VSILFILE *fp = VSIFileFromMemBuffer( osResultFilename,
121 : psResult->pabyData,
122 : psResult->nDataLen,
123 2 : TRUE );
124 :
125 2 : if( fp == NULL )
126 0 : return NULL;
127 :
128 2 : VSIFCloseL( fp );
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* Steal the memory buffer from HTTP result before destroying */
132 : /* it. */
133 : /* -------------------------------------------------------------------- */
134 2 : psResult->pabyData = NULL;
135 2 : psResult->nDataLen = psResult->nDataAlloc = 0;
136 :
137 2 : CPLHTTPDestroyResult( psResult );
138 :
139 : /* -------------------------------------------------------------------- */
140 : /* Try opening this result as a gdaldataset. */
141 : /* -------------------------------------------------------------------- */
142 : GDALDataset *poDS = (GDALDataset *)
143 2 : GDALOpen( osResultFilename, GA_ReadOnly );
144 :
145 : /* -------------------------------------------------------------------- */
146 : /* If opening it in memory didn't work, perhaps we need to */
147 : /* write to a temp file on disk? */
148 : /* -------------------------------------------------------------------- */
149 2 : if( poDS == NULL )
150 : {
151 1 : CPLString osTempFilename;
152 :
153 1 : osTempFilename.Printf( "/tmp/%s", CPLGetFilename(osResultFilename) );
154 1 : if( CPLCopyFile( osTempFilename, osResultFilename ) != 0 )
155 : {
156 : CPLError( CE_Failure, CPLE_OpenFailed,
157 : "Failed to create temporary file:%s",
158 0 : osTempFilename.c_str() );
159 : }
160 : else
161 : {
162 : poDS = (GDALDataset *)
163 1 : GDALOpen( osTempFilename, GA_ReadOnly );
164 1 : VSIUnlink( osTempFilename ); /* this may not work on windows */
165 1 : }
166 : }
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* Release our hold on the vsi memory file, though if it is */
170 : /* held open by a dataset it will continue to exist till that */
171 : /* lets it go. */
172 : /* -------------------------------------------------------------------- */
173 2 : VSIUnlink( osResultFilename );
174 :
175 2 : return poDS;
176 : }
177 :
178 : /************************************************************************/
179 : /* GDALRegister_HTTP() */
180 : /************************************************************************/
181 :
182 558 : void GDALRegister_HTTP()
183 :
184 : {
185 : GDALDriver *poDriver;
186 :
187 558 : if( GDALGetDriverByName( "HTTP" ) == NULL )
188 : {
189 537 : poDriver = new GDALDriver();
190 :
191 537 : poDriver->SetDescription( "HTTP" );
192 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
193 537 : "HTTP Fetching Wrapper" );
194 :
195 537 : poDriver->pfnOpen = HTTPOpen;
196 :
197 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
198 : }
199 558 : }
|