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-2016 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%    http://www.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__) && !defined(__MINGW64__)
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__) || defined(__MINGW64__))
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)
105extern "C" {
106#endif
107
108#if defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_FTP_ENABLED)
109static 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
131static Image *ReadURLImage(const ImageInfo *image_info,ExceptionInfo *exception)
132{
133#define MaxBufferExtent  8192
134
135  char
136    filename[MagickPathExtent];
137
138  FILE
139    *file;
140
141  Image
142    *image;
143
144  ImageInfo
145    *read_info;
146
147  int
148    unique_file;
149
150  read_info=CloneImageInfo(image_info);
151  SetImageInfoBlob(read_info,(void *) NULL,0);
152  if (LocaleCompare(read_info->magick,"file") == 0)
153    {
154      (void) CopyMagickString(read_info->filename,image_info->filename+2,
155        MagickPathExtent);
156      *read_info->magick='\0';
157      image=ReadImage(read_info,exception);
158      read_info=DestroyImageInfo(read_info);
159      return(GetFirstImageInList(image));
160    }
161  file=(FILE *) NULL;
162  unique_file=AcquireUniqueFileResource(read_info->filename);
163  if (unique_file != -1)
164    file=fdopen(unique_file,"wb");
165  if ((unique_file == -1) || (file == (FILE *) NULL))
166    {
167      ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
168        read_info->filename);
169      read_info=DestroyImageInfo(read_info);
170      return((Image *) NULL);
171    }
172  (void) CopyMagickString(filename,image_info->magick,MagickPathExtent);
173  (void) ConcatenateMagickString(filename,":",MagickPathExtent);
174  LocaleLower(filename);
175  (void) ConcatenateMagickString(filename,image_info->filename,
176    MagickPathExtent);
177#if defined(MAGICKCORE_WINDOWS_SUPPORT) && \
178    !(defined(__MINGW32__) || defined(__MINGW64__))
179  (void) fclose(file);
180  if (URLDownloadToFile(NULL,filename,read_info->filename,0,NULL) != S_OK)
181    {
182      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
183        filename);
184      (void) RelinquishUniqueFileResource(read_info->filename);
185      read_info=DestroyImageInfo(read_info);
186      return((Image *) NULL);
187    }
188#else
189#if defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_FTP_ENABLED)
190  if (LocaleCompare(read_info->magick,"ftp") == 0)
191    {
192      void
193        *context;
194
195      xmlNanoFTPInit();
196      context=xmlNanoFTPNewCtxt(filename);
197      if (context != (void *) NULL)
198        {
199          if (xmlNanoFTPConnect(context) >= 0)
200            (void) xmlNanoFTPGet(context,GetFTPData,(void *) file,
201              (char *) NULL);
202          (void) xmlNanoFTPClose(context);
203        }
204    }
205#endif
206#if defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_HTTP_ENABLED)
207  if (LocaleCompare(read_info->magick,"http") == 0)
208    {
209      char
210        buffer[MaxBufferExtent],
211        *type;
212
213      int
214        bytes;
215
216      void
217        *context;
218
219      type=(char *) NULL;
220      context=xmlNanoHTTPMethod(filename,(const char *) NULL,
221        (const char *) NULL,&type,(const char *) NULL,0);
222      if (context != (void *) NULL)
223        {
224          ssize_t
225            count;
226
227          while ((bytes=xmlNanoHTTPRead(context,buffer,MaxBufferExtent)) > 0)
228            count=(ssize_t) fwrite(buffer,bytes,1,file);
229          (void) count;
230          xmlNanoHTTPClose(context);
231          xmlFree(type);
232          xmlNanoHTTPCleanup();
233        }
234    }
235#endif
236  (void) fclose(file);
237#endif
238  *read_info->magick='\0';
239  image=ReadImage(read_info,exception);
240  (void) RelinquishUniqueFileResource(read_info->filename);
241  read_info=DestroyImageInfo(read_info);
242  if (image != (Image *) NULL)
243    GetPathComponent(image_info->filename,TailPath,image->filename);
244  else
245    {
246      (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
247        "NoDataReturned","`%s'",filename);
248      return((Image *) NULL);
249    }
250  return(GetFirstImageInList(image));
251}
252
253/*
254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255%                                                                             %
256%                                                                             %
257%                                                                             %
258%   R e g i s t e r U R L I m a g e                                           %
259%                                                                             %
260%                                                                             %
261%                                                                             %
262%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263%
264%  RegisterURLImage() adds attributes for the URL image format to
265%  the list of supported formats.  The attributes include the image format
266%  tag, a method to read and/or write the format, whether the format
267%  supports the saving of more than one frame to the same file or blob,
268%  whether the format supports native in-memory I/O, and a brief
269%  description of the format.
270%
271%  The format of the RegisterURLImage method is:
272%
273%      size_t RegisterURLImage(void)
274%
275*/
276ModuleExport size_t RegisterURLImage(void)
277{
278  MagickInfo
279    *entry;
280
281  entry=AcquireMagickInfo("URL","HTTP","Uniform Resource Locator (http://)");
282#if (defined(MAGICKCORE_WINDOWS_SUPPORT) && \
283    !(defined(__MINGW32__) || defined(__MINGW64__))) || \
284    (defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_HTTP_ENABLED))
285  entry->decoder=(DecodeImageHandler *) ReadURLImage;
286#endif
287  entry->format_type=ImplicitFormatType;
288  (void) RegisterMagickInfo(entry);
289  entry=AcquireMagickInfo("URL","HTTPS","Uniform Resource Locator (https://)");
290#if defined(MAGICKCORE_WINDOWS_SUPPORT) && \
291    !(defined(__MINGW32__) || defined(__MINGW64__))
292  entry->decoder=(DecodeImageHandler *) ReadURLImage;
293#endif
294  entry->format_type=ImplicitFormatType;
295  (void) RegisterMagickInfo(entry);
296  entry=AcquireMagickInfo("URL","FTP","Uniform Resource Locator (ftp://)");
297#if (defined(MAGICKCORE_WINDOWS_SUPPORT) && \
298    !(defined(__MINGW32__) || defined(__MINGW64__))) || \
299    (defined(MAGICKCORE_XML_DELEGATE) && defined(LIBXML_FTP_ENABLED))
300  entry->decoder=(DecodeImageHandler *) ReadURLImage;
301#endif
302  entry->format_type=ImplicitFormatType;
303  (void) RegisterMagickInfo(entry);
304  entry=AcquireMagickInfo("URL","FILE","Uniform Resource Locator (file://)");
305  entry->decoder=(DecodeImageHandler *) ReadURLImage;
306  entry->format_type=ImplicitFormatType;
307  (void) RegisterMagickInfo(entry);
308  return(MagickImageCoderSignature);
309}
310
311/*
312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313%                                                                             %
314%                                                                             %
315%                                                                             %
316%   U n r e g i s t e r U R L I m a g e                                       %
317%                                                                             %
318%                                                                             %
319%                                                                             %
320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321%
322%  UnregisterURLImage() removes format registrations made by the
323%  URL module from the list of supported formats.
324%
325%  The format of the UnregisterURLImage method is:
326%
327%      UnregisterURLImage(void)
328%
329*/
330ModuleExport void UnregisterURLImage(void)
331{
332  (void) UnregisterMagickInfo("HTTP");
333  (void) UnregisterMagickInfo("FTP");
334  (void) UnregisterMagickInfo("FILE");
335}
336