1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % U U RRRR L %
7 % U U R R L %
8 % U U RRRR L %
9 % U U R R L %
10 % UUU R R LLLLL %
11 % %
12 % %
13 % Retrieve An Image Via URL. %
14 % %
15 % Software Design %
16 % Cristy %
17 % Bill Radcliffe %
18 % March 2000 %
19 % %
20 % %
21 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
23 % %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
26 % %
27 % https://imagemagick.org/script/license.php %
28 % %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
34 % %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 */
39
40 /*
41 Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/constitute.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/image.h"
50 #include "MagickCore/image-private.h"
51 #include "MagickCore/list.h"
52 #include "MagickCore/magick.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/module.h"
55 #include "MagickCore/quantum-private.h"
56 #include "MagickCore/static.h"
57 #include "MagickCore/resource_.h"
58 #include "MagickCore/string_.h"
59 #include "MagickCore/utility.h"
60 #if defined(MAGICKCORE_XML_DELEGATE)
61 # if defined(MAGICKCORE_WINDOWS_SUPPORT)
62 # if !defined(__MINGW32__)
63 # include <win32config.h>
64 # endif
65 # endif
66 # include <libxml/parser.h>
67 # include <libxml/xmlmemory.h>
68 # include <libxml/nanoftp.h>
69 # include <libxml/nanohttp.h>
70 #endif
71 #if defined(MAGICKCORE_WINDOWS_SUPPORT) && \
72 !defined(__MINGW32__)
73 # include <urlmon.h>
74 # pragma comment(lib, "urlmon.lib")
75 #endif
76
77 /*
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 % %
80 % %
81 % %
82 % R e a d U R L I m a g e %
83 % %
84 % %
85 % %
86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 %
88 % ReadURLImage retrieves an image via URL, decodes the image, and returns
89 % it. It allocates the memory necessary for the new Image structure and
90 % returns a pointer to the new image.
91 %
92 % The format of the ReadURLImage method is:
93 %
94 % Image *ReadURLImage(const ImageInfo *image_info,ExceptionInfo *exception)
95 %
96 % A description of each parameter follows:
97 %
98 % o image_info: the image info.
99 %
100 % o exception: return any errors or warnings in this structure.
101 %
102 */
103
104 #if defined(__cplusplus) || defined(c_plusplus)
105 extern "C" {
106 #endif
107
108 #if defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_FTP_ENABLED)
GetFTPData(void * userdata,const char * data,int size)109 static void GetFTPData(void *userdata,const char *data,int size)
110 {
111 FILE
112 *file;
113
114 size_t
115 length;
116
117 file=(FILE *) userdata;
118 if (file == (FILE *) NULL)
119 return;
120 if (size <= 0)
121 return;
122 length=fwrite(data,size,1,file);
123 (void) length;
124 }
125 #endif
126
127 #if defined(__cplusplus) || defined(c_plusplus)
128 }
129 #endif
130
ReadURLImage(const ImageInfo * image_info,ExceptionInfo * exception)131 static Image *ReadURLImage(const ImageInfo *image_info,ExceptionInfo *exception)
132 {
133 char
134 filename[MagickPathExtent];
135
136 FILE
137 *file;
138
139 Image
140 *image,
141 *images,
142 *next;
143
144 ImageInfo
145 *read_info;
146
147 int
148 unique_file;
149
150 images=(Image *) NULL;
151 image=AcquireImage(image_info,exception);
152 read_info=CloneImageInfo(image_info);
153 SetImageInfoBlob(read_info,(void *) NULL,0);
154 #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
155 if (LocaleCompare(read_info->magick,"https") == 0)
156 {
157 MagickBooleanType
158 status;
159
160 /*
161 Leverage delegate to read HTTPS link.
162 */
163 status=InvokeDelegate(read_info,image,"https:decode",(char *) NULL,
164 exception);
165 if (status != MagickFalse)
166 {
167 (void) FormatLocaleString(read_info->filename,MagickPathExtent,
168 "%s.dat",read_info->unique);
169 *read_info->magick='\0';
170 images=ReadImage(read_info,exception);
171 (void) RelinquishUniqueFileResource(read_info->filename);
172 if (images != (Image *) NULL)
173 for (next=images; next != (Image *) NULL; next=next->next)
174 (void) CopyMagickString(next->filename,image->filename,
175 MagickPathExtent);
176 }
177 read_info=DestroyImageInfo(read_info);
178 image=DestroyImage(image);
179 return(images);
180 }
181 #endif
182 if (LocaleCompare(read_info->magick,"file") == 0)
183 {
184 (void) CopyMagickString(read_info->filename,image_info->filename+2,
185 MagickPathExtent);
186 *read_info->magick='\0';
187 images=ReadImage(read_info,exception);
188 read_info=DestroyImageInfo(read_info);
189 image=DestroyImage(image);
190 return(GetFirstImageInList(images));
191 }
192 file=(FILE *) NULL;
193 unique_file=AcquireUniqueFileResource(read_info->filename);
194 if (unique_file != -1)
195 file=fdopen(unique_file,"wb");
196 if ((unique_file == -1) || (file == (FILE *) NULL))
197 {
198 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
199 read_info->filename);
200 read_info=DestroyImageInfo(read_info);
201 image=DestroyImage(image);
202 return((Image *) NULL);
203 }
204 (void) CopyMagickString(filename,image_info->magick,MagickPathExtent);
205 (void) ConcatenateMagickString(filename,":",MagickPathExtent);
206 LocaleLower(filename);
207 (void) ConcatenateMagickString(filename,image_info->filename,
208 MagickPathExtent);
209 #if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
210 (void) fclose(file);
211 if (URLDownloadToFile(NULL,filename,read_info->filename,0,NULL) != S_OK)
212 {
213 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
214 filename);
215 (void) RelinquishUniqueFileResource(read_info->filename);
216 read_info=DestroyImageInfo(read_info);
217 image=DestroyImage(image);
218 return((Image *) NULL);
219 }
220 #else
221 #if defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_FTP_ENABLED)
222 if (LocaleCompare(read_info->magick,"ftp") == 0)
223 {
224 void
225 *context;
226
227 xmlNanoFTPInit();
228 context=xmlNanoFTPNewCtxt(filename);
229 if (context != (void *) NULL)
230 {
231 if (xmlNanoFTPConnect(context) >= 0)
232 (void) xmlNanoFTPGet(context,GetFTPData,(void *) file,
233 (char *) NULL);
234 (void) xmlNanoFTPClose(context);
235 }
236 }
237 #endif
238 #if defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_HTTP_ENABLED)
239 if (LocaleCompare(read_info->magick,"http") == 0)
240 {
241 char
242 buffer[8192],
243 *type;
244
245 int
246 bytes;
247
248 void
249 *context;
250
251 type=(char *) NULL;
252 context=xmlNanoHTTPMethod(filename,(const char *) NULL,
253 (const char *) NULL,&type,(const char *) NULL,0);
254 if (context != (void *) NULL)
255 {
256 ssize_t
257 count;
258
259 while ((bytes=xmlNanoHTTPRead(context,buffer,sizeof(buffer))) > 0)
260 count=(ssize_t) fwrite(buffer,bytes,1,file);
261 (void) count;
262 xmlNanoHTTPClose(context);
263 xmlFree(type);
264 xmlNanoHTTPCleanup();
265 }
266 }
267 #endif
268 (void) fclose(file);
269 #endif
270 *read_info->magick='\0';
271 images=ReadImage(read_info,exception);
272 (void) RelinquishUniqueFileResource(read_info->filename);
273 if (images != (Image *) NULL)
274 for (next=images; next != (Image *) NULL; next=next->next)
275 (void) CopyMagickString(next->filename,image->filename,MagickPathExtent);
276 read_info=DestroyImageInfo(read_info);
277 image=DestroyImage(image);
278 if (images != (Image *) NULL)
279 GetPathComponent(image_info->filename,TailPath,images->filename);
280 else
281 {
282 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
283 "NoDataReturned","`%s'",filename);
284 return((Image *) NULL);
285 }
286 return(GetFirstImageInList(images));
287 }
288
289 /*
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291 % %
292 % %
293 % %
294 % R e g i s t e r U R L I m a g e %
295 % %
296 % %
297 % %
298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299 %
300 % RegisterURLImage() adds attributes for the URL image format to
301 % the list of supported formats. The attributes include the image format
302 % tag, a method to read and/or write the format, whether the format
303 % supports the saving of more than one frame to the same file or blob,
304 % whether the format supports native in-memory I/O, and a brief
305 % description of the format.
306 %
307 % The format of the RegisterURLImage method is:
308 %
309 % size_t RegisterURLImage(void)
310 %
311 */
RegisterURLImage(void)312 ModuleExport size_t RegisterURLImage(void)
313 {
314 MagickInfo
315 *entry;
316
317 entry=AcquireMagickInfo("URL","HTTP","Uniform Resource Locator (http://)");
318 #if (defined(MAGICKCORE_WINDOWS_SUPPORT) && \
319 !defined(__MINGW32__)) || \
320 (defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_HTTP_ENABLED))
321 entry->decoder=(DecodeImageHandler *) ReadURLImage;
322 #endif
323 entry->format_type=ImplicitFormatType;
324 (void) RegisterMagickInfo(entry);
325 entry=AcquireMagickInfo("URL","HTTPS","Uniform Resource Locator (https://)");
326 entry->decoder=(DecodeImageHandler *) ReadURLImage;
327 entry->format_type=ImplicitFormatType;
328 (void) RegisterMagickInfo(entry);
329 entry=AcquireMagickInfo("URL","FTP","Uniform Resource Locator (ftp://)");
330 #if (defined(MAGICKCORE_WINDOWS_SUPPORT) && \
331 !defined(__MINGW32__)) || \
332 (defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_FTP_ENABLED))
333 entry->decoder=(DecodeImageHandler *) ReadURLImage;
334 #endif
335 entry->format_type=ImplicitFormatType;
336 (void) RegisterMagickInfo(entry);
337 entry=AcquireMagickInfo("URL","FILE","Uniform Resource Locator (file://)");
338 entry->decoder=(DecodeImageHandler *) ReadURLImage;
339 entry->format_type=ImplicitFormatType;
340 (void) RegisterMagickInfo(entry);
341 return(MagickImageCoderSignature);
342 }
343
344 /*
345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 % %
347 % %
348 % %
349 % U n r e g i s t e r U R L I m a g e %
350 % %
351 % %
352 % %
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 %
355 % UnregisterURLImage() removes format registrations made by the
356 % URL module from the list of supported formats.
357 %
358 % The format of the UnregisterURLImage method is:
359 %
360 % UnregisterURLImage(void)
361 %
362 */
UnregisterURLImage(void)363 ModuleExport void UnregisterURLImage(void)
364 {
365 (void) UnregisterMagickInfo("HTTP");
366 (void) UnregisterMagickInfo("FTP");
367 (void) UnregisterMagickInfo("FILE");
368 }
369