OpenShot Library | libopenshot-audio  0.2.0
juce_URL.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
27  public Thread
28 {
29  FallbackDownloadTask (FileOutputStream* outputStreamToUse,
30  size_t bufferSizeToUse,
31  WebInputStream* streamToUse,
32  URL::DownloadTask::Listener* listenerToUse)
33  : Thread ("DownloadTask thread"),
34  fileStream (outputStreamToUse),
35  stream (streamToUse),
36  bufferSize (bufferSizeToUse),
37  buffer (bufferSize),
38  listener (listenerToUse)
39  {
40  jassert (fileStream != nullptr);
41  jassert (stream != nullptr);
42 
43  targetLocation = fileStream->getFile();
44  contentLength = stream->getTotalLength();
45  httpCode = stream->getStatusCode();
46 
47  startThread();
48  }
49 
50  ~FallbackDownloadTask() override
51  {
53  stream->cancel();
55  }
56 
57  //==============================================================================
58  void run() override
59  {
60  while (! (stream->isExhausted() || stream->isError() || threadShouldExit()))
61  {
62  if (listener != nullptr)
63  listener->progress (this, downloaded, contentLength);
64 
65  auto max = jmin ((int) bufferSize, contentLength < 0 ? std::numeric_limits<int>::max()
66  : static_cast<int> (contentLength - downloaded));
67 
68  auto actual = stream->read (buffer.get(), max);
69 
70  if (actual < 0 || threadShouldExit() || stream->isError())
71  break;
72 
73  if (! fileStream->write (buffer.get(), static_cast<size_t> (actual)))
74  {
75  error = true;
76  break;
77  }
78 
79  downloaded += actual;
80 
81  if (downloaded == contentLength)
82  break;
83  }
84 
85  fileStream->flush();
86 
87  if (threadShouldExit() || stream->isError())
88  error = true;
89 
90  if (contentLength > 0 && downloaded < contentLength)
91  error = true;
92 
93  finished = true;
94 
95  if (listener != nullptr && ! threadShouldExit())
96  listener->finished (this, ! error);
97  }
98 
99  //==============================================================================
100  const std::unique_ptr<FileOutputStream> fileStream;
101  const std::unique_ptr<WebInputStream> stream;
102  const size_t bufferSize;
103  HeapBlock<char> buffer;
104  URL::DownloadTask::Listener* const listener;
105 
106  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FallbackDownloadTask)
107 };
108 
110 URL::DownloadTask::Listener::~Listener() {}
111 
112 //==============================================================================
113 URL::DownloadTask* URL::DownloadTask::createFallbackDownloader (const URL& urlToUse,
114  const File& targetFileToUse,
115  const String& extraHeadersToUse,
116  Listener* listenerToUse,
117  bool usePostRequest)
118 {
119  const size_t bufferSize = 0x8000;
120  targetFileToUse.deleteFile();
121 
122  if (auto outputStream = std::unique_ptr<FileOutputStream> (targetFileToUse.createOutputStream (bufferSize)))
123  {
124  std::unique_ptr<WebInputStream> stream (new WebInputStream (urlToUse, usePostRequest));
125  stream->withExtraHeaders (extraHeadersToUse);
126 
127  if (stream->connect (nullptr))
128  return new FallbackDownloadTask (outputStream.release(), bufferSize, stream.release(), listenerToUse);
129  }
130 
131  return nullptr;
132 }
133 
134 URL::DownloadTask::DownloadTask() {}
136 
137 //==============================================================================
138 URL::URL() noexcept {}
139 
140 URL::URL (const String& u) : url (u)
141 {
142  init();
143 }
144 
145 URL::URL (File localFile)
146 {
147  if (localFile == File())
148  return;
149 
150  #if JUCE_WINDOWS
151  bool isUncPath = localFile.getFullPathName().startsWith ("\\\\");
152  #endif
153 
154  while (! localFile.isRoot())
155  {
156  url = "/" + addEscapeChars (localFile.getFileName(), false) + url;
157  localFile = localFile.getParentDirectory();
158  }
159 
160  url = addEscapeChars (localFile.getFileName(), false) + url;
161 
162  #if JUCE_WINDOWS
163  if (isUncPath)
164  {
165  url = url.fromFirstOccurrenceOf ("/", false, false);
166  }
167  else
168  #endif
169  {
170  if (! url.startsWithChar (L'/'))
171  url = "/" + url;
172  }
173 
174 
175  url = "file://" + url;
176 
177  jassert (isWellFormed());
178 }
179 
180 void URL::init()
181 {
182  auto i = url.indexOfChar ('?');
183 
184  if (i >= 0)
185  {
186  do
187  {
188  auto nextAmp = url.indexOfChar (i + 1, '&');
189  auto equalsPos = url.indexOfChar (i + 1, '=');
190 
191  if (nextAmp < 0)
192  {
193  addParameter (removeEscapeChars (equalsPos < 0 ? url.substring (i + 1) : url.substring (i + 1, equalsPos)),
194  equalsPos < 0 ? String() : removeEscapeChars (url.substring (equalsPos + 1)));
195  }
196  else if (nextAmp > 0 && equalsPos < nextAmp)
197  {
198  addParameter (removeEscapeChars (equalsPos < 0 ? url.substring (i + 1, nextAmp) : url.substring (i + 1, equalsPos)),
199  equalsPos < 0 ? String() : removeEscapeChars (url.substring (equalsPos + 1, nextAmp)));
200  }
201 
202  i = nextAmp;
203  }
204  while (i >= 0);
205 
206  url = url.upToFirstOccurrenceOf ("?", false, false);
207  }
208 }
209 
210 URL::URL (const String& u, int) : url (u) {}
211 
212 URL::URL (URL&& other)
213  : url (std::move (other.url)),
214  postData (std::move (other.postData)),
215  parameterNames (std::move (other.parameterNames)),
216  parameterValues (std::move (other.parameterValues)),
217  filesToUpload (std::move (other.filesToUpload))
218  #if JUCE_IOS
219  , bookmark (std::move (other.bookmark))
220  #endif
221 {
222 }
223 
224 URL& URL::operator= (URL&& other)
225 {
226  url = std::move (other.url);
227  postData = std::move (other.postData);
228  parameterNames = std::move (other.parameterNames);
229  parameterValues = std::move (other.parameterValues);
230  filesToUpload = std::move (other.filesToUpload);
231  #if JUCE_IOS
232  bookmark = std::move (other.bookmark);
233  #endif
234 
235  return *this;
236 }
237 
239 
241 {
242  return URL (u, 0);
243 }
244 
245 bool URL::operator== (const URL& other) const
246 {
247  return url == other.url
248  && postData == other.postData
249  && parameterNames == other.parameterNames
250  && parameterValues == other.parameterValues
251  && filesToUpload == other.filesToUpload;
252 }
253 
254 bool URL::operator!= (const URL& other) const
255 {
256  return ! operator== (other);
257 }
258 
259 namespace URLHelpers
260 {
261  static String getMangledParameters (const URL& url)
262  {
263  jassert (url.getParameterNames().size() == url.getParameterValues().size());
264  String p;
265 
266  for (int i = 0; i < url.getParameterNames().size(); ++i)
267  {
268  if (i > 0)
269  p << '&';
270 
271  auto val = url.getParameterValues()[i];
272 
273  p << URL::addEscapeChars (url.getParameterNames()[i], true);
274 
275  if (val.isNotEmpty())
276  p << '=' << URL::addEscapeChars (val, true);
277  }
278 
279  return p;
280  }
281 
282  static int findEndOfScheme (const String& url)
283  {
284  int i = 0;
285 
287  || url[i] == '+' || url[i] == '-' || url[i] == '.')
288  ++i;
289 
290  return url.substring (i).startsWith ("://") ? i + 1 : 0;
291  }
292 
293  static int findStartOfNetLocation (const String& url)
294  {
295  int start = findEndOfScheme (url);
296 
297  while (url[start] == '/')
298  ++start;
299 
300  return start;
301  }
302 
303  static int findStartOfPath (const String& url)
304  {
305  return url.indexOfChar (findStartOfNetLocation (url), '/') + 1;
306  }
307 
308  static void concatenatePaths (String& path, const String& suffix)
309  {
310  if (! path.endsWithChar ('/'))
311  path << '/';
312 
313  if (suffix.startsWithChar ('/'))
314  path += suffix.substring (1);
315  else
316  path += suffix;
317  }
318 }
319 
320 void URL::addParameter (const String& name, const String& value)
321 {
322  parameterNames.add (name);
323  parameterValues.add (value);
324 }
325 
326 String URL::toString (bool includeGetParameters) const
327 {
328  if (includeGetParameters && parameterNames.size() > 0)
329  return url + "?" + URLHelpers::getMangledParameters (*this);
330 
331  return url;
332 }
333 
334 bool URL::isEmpty() const noexcept
335 {
336  return url.isEmpty();
337 }
338 
339 bool URL::isWellFormed() const
340 {
341  //xxx TODO
342  return url.isNotEmpty();
343 }
344 
346 {
347  return getDomainInternal (false);
348 }
349 
351 {
352  auto startOfPath = URLHelpers::findStartOfPath (url);
353 
354  return startOfPath <= 0 ? String()
355  : url.substring (startOfPath);
356 }
357 
359 {
360  return url.substring (0, URLHelpers::findEndOfScheme (url) - 1);
361 }
362 
363 #ifndef JUCE_ANDROID
364 bool URL::isLocalFile() const
365 {
366  return (getScheme() == "file");
367 }
368 
369 File URL::getLocalFile() const
370 {
371  return fileFromFileSchemeURL (*this);
372 }
373 
374 String URL::getFileName() const
375 {
376  return toString (false).fromLastOccurrenceOf ("/", false, true);
377 }
378 #endif
379 
380 File URL::fileFromFileSchemeURL (const URL& fileURL)
381 {
382  if (! fileURL.isLocalFile())
383  {
384  jassertfalse;
385  return {};
386  }
387 
388  auto path = removeEscapeChars (fileURL.getDomainInternal (true)).replace ("+", "%2B");
389 
390  #ifdef JUCE_WINDOWS
391  bool isUncPath = (! fileURL.url.startsWith ("file:///"));
392  #else
393  path = File::getSeparatorString() + path;
394  #endif
395 
396  auto urlElements = StringArray::fromTokens (fileURL.getSubPath(), "/", "");
397 
398  for (auto urlElement : urlElements)
399  path += File::getSeparatorString() + removeEscapeChars (urlElement.replace ("+", "%2B"));
400 
401  #ifdef JUCE_WINDOWS
402  if (isUncPath)
403  path = "\\\\" + path;
404  #endif
405 
406  return path;
407 }
408 
409 int URL::getPort() const
410 {
411  auto colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url), ':');
412 
413  return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0;
414 }
415 
416 URL URL::withNewDomainAndPath (const String& newURL) const
417 {
418  URL u (*this);
419  u.url = newURL;
420  return u;
421 }
422 
423 URL URL::withNewSubPath (const String& newPath) const
424 {
425  const int startOfPath = URLHelpers::findStartOfPath (url);
426 
427  URL u (*this);
428 
429  if (startOfPath > 0)
430  u.url = url.substring (0, startOfPath);
431 
432  URLHelpers::concatenatePaths (u.url, newPath);
433  return u;
434 }
435 
436 URL URL::getChildURL (const String& subPath) const
437 {
438  URL u (*this);
439  URLHelpers::concatenatePaths (u.url, subPath);
440  return u;
441 }
442 
443 void URL::createHeadersAndPostData (String& headers, MemoryBlock& postDataToWrite) const
444 {
445  MemoryOutputStream data (postDataToWrite, false);
446 
447  if (filesToUpload.size() > 0)
448  {
449  // (this doesn't currently support mixing custom post-data with uploads..)
450  jassert (postData.getSize() == 0);
451 
452  auto boundary = String::toHexString (Random::getSystemRandom().nextInt64());
453 
454  headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n";
455 
456  data << "--" << boundary;
457 
458  for (int i = 0; i < parameterNames.size(); ++i)
459  {
460  data << "\r\nContent-Disposition: form-data; name=\"" << parameterNames[i]
461  << "\"\r\n\r\n" << parameterValues[i]
462  << "\r\n--" << boundary;
463  }
464 
465  for (auto* f : filesToUpload)
466  {
467  data << "\r\nContent-Disposition: form-data; name=\"" << f->parameterName
468  << "\"; filename=\"" << f->filename << "\"\r\n";
469 
470  if (f->mimeType.isNotEmpty())
471  data << "Content-Type: " << f->mimeType << "\r\n";
472 
473  data << "Content-Transfer-Encoding: binary\r\n\r\n";
474 
475  if (f->data != nullptr)
476  data << *f->data;
477  else
478  data << f->file;
479 
480  data << "\r\n--" << boundary;
481  }
482 
483  data << "--\r\n";
484  }
485  else
486  {
487  data << URLHelpers::getMangledParameters (*this)
488  << postData;
489 
490  // if the user-supplied headers didn't contain a content-type, add one now..
491  if (! headers.containsIgnoreCase ("Content-Type"))
492  headers << "Content-Type: application/x-www-form-urlencoded\r\n";
493 
494  headers << "Content-length: " << (int) data.getDataSize() << "\r\n";
495  }
496 }
497 
498 //==============================================================================
499 bool URL::isProbablyAWebsiteURL (const String& possibleURL)
500 {
501  static const char* validProtocols[] = { "http:", "ftp:", "https:" };
502 
503  for (auto* protocol : validProtocols)
504  if (possibleURL.startsWithIgnoreCase (protocol))
505  return true;
506 
507  if (possibleURL.containsChar ('@')
508  || possibleURL.containsChar (' '))
509  return false;
510 
511  const String topLevelDomain (possibleURL.upToFirstOccurrenceOf ("/", false, false)
512  .fromLastOccurrenceOf (".", false, false));
513 
514  return topLevelDomain.isNotEmpty() && topLevelDomain.length() <= 3;
515 }
516 
517 bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress)
518 {
519  auto atSign = possibleEmailAddress.indexOfChar ('@');
520 
521  return atSign > 0
522  && possibleEmailAddress.lastIndexOfChar ('.') > (atSign + 1)
523  && ! possibleEmailAddress.endsWithChar ('.');
524 }
525 
526 String URL::getDomainInternal (bool ignorePort) const
527 {
528  auto start = URLHelpers::findStartOfNetLocation (url);
529  auto end1 = url.indexOfChar (start, '/');
530  auto end2 = ignorePort ? -1 : url.indexOfChar (start, ':');
531 
532  auto end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
533  : ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
534  : jmin (end1, end2));
535  return url.substring (start, end);
536 }
537 
538 #if JUCE_IOS
539 URL::Bookmark::Bookmark (void* bookmarkToUse)
540  : data (bookmarkToUse)
541 {
542 }
543 
544 URL::Bookmark::~Bookmark()
545 {
546  [(NSData*) data release];
547 }
548 
549 void setURLBookmark (URL& u, void* bookmark)
550 {
551  u.bookmark = new URL::Bookmark (bookmark);
552 }
553 
554 void* getURLBookmark (URL& u)
555 {
556  if (u.bookmark.get() == nullptr)
557  return nullptr;
558 
559  return u.bookmark.get()->data;
560 }
561 
562 template <typename Stream> struct iOSFileStreamWrapperFlush { static void flush (Stream*) {} };
563 template <> struct iOSFileStreamWrapperFlush<FileOutputStream> { static void flush (OutputStream* o) { o->flush(); } };
564 
565 template <typename Stream>
566 class iOSFileStreamWrapper : public Stream
567 {
568 public:
569  iOSFileStreamWrapper (URL& urlToUse)
570  : Stream (getLocalFileAccess (urlToUse)),
571  url (urlToUse)
572  {}
573 
575  {
577 
578  if (NSData* bookmark = (NSData*) getURLBookmark (url))
579  {
580  BOOL isBookmarkStale = false;
581  NSError* error = nil;
582 
583  auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
584  options: 0
585  relativeToURL: nil
586  bookmarkDataIsStale: &isBookmarkStale
587  error: &error];
588 
589  if (error == nil)
590  {
591  if (isBookmarkStale)
592  updateStaleBookmark (nsURL, url);
593 
594  [nsURL stopAccessingSecurityScopedResource];
595  }
596  else
597  {
598  auto desc = [error localizedDescription];
599  ignoreUnused (desc);
600  jassertfalse;
601  }
602  }
603  }
604 
605 private:
606  URL url;
607  bool securityAccessSucceeded = false;
608 
609  File getLocalFileAccess (URL& urlToUse)
610  {
611  if (NSData* bookmark = (NSData*) getURLBookmark (urlToUse))
612  {
613  BOOL isBookmarkStale = false;
614  NSError* error = nil;
615 
616  auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
617  options: 0
618  relativeToURL: nil
619  bookmarkDataIsStale: &isBookmarkStale
620  error: &error];
621 
622  if (error == nil)
623  {
624  securityAccessSucceeded = [nsURL startAccessingSecurityScopedResource];
625 
626  if (isBookmarkStale)
627  updateStaleBookmark (nsURL, urlToUse);
628 
629  return urlToUse.getLocalFile();
630  }
631  else
632  {
633  auto desc = [error localizedDescription];
634  ignoreUnused (desc);
635  jassertfalse;
636  }
637  }
638 
639  return urlToUse.getLocalFile();
640  }
641 
642  void updateStaleBookmark (NSURL* nsURL, URL& juceUrl)
643  {
644  NSError* error = nil;
645 
646  NSData* bookmark = [nsURL bookmarkDataWithOptions: NSURLBookmarkCreationSuitableForBookmarkFile
647  includingResourceValuesForKeys: nil
648  relativeToURL: nil
649  error: &error];
650 
651  if (error == nil)
652  setURLBookmark (juceUrl, (void*) bookmark);
653  else
654  jassertfalse;
655  }
656 };
657 #endif
658 
659 //==============================================================================
660 InputStream* URL::createInputStream (bool usePostCommand,
661  OpenStreamProgressCallback* progressCallback,
662  void* progressCallbackContext,
663  String headers,
664  int timeOutMs,
665  StringPairArray* responseHeaders,
666  int* statusCode,
667  int numRedirectsToFollow,
668  String httpRequestCmd) const
669 {
670  if (isLocalFile())
671  {
672  #if JUCE_IOS
673  // We may need to refresh the embedded bookmark.
674  return new iOSFileStreamWrapper<FileInputStream> (const_cast<URL&>(*this));
675  #else
676  return getLocalFile().createInputStream();
677  #endif
678 
679  }
680 
681  std::unique_ptr<WebInputStream> wi (new WebInputStream (*this, usePostCommand));
682 
683  struct ProgressCallbackCaller : public WebInputStream::Listener
684  {
685  ProgressCallbackCaller (OpenStreamProgressCallback* progressCallbackToUse, void* progressCallbackContextToUse)
686  : callback (progressCallbackToUse), data (progressCallbackContextToUse)
687  {}
688 
689  bool postDataSendProgress (WebInputStream&, int bytesSent, int totalBytes) override
690  {
691  return callback (data, bytesSent, totalBytes);
692  }
693 
694  OpenStreamProgressCallback* callback;
695  void* const data;
696 
697  // workaround a MSVC 2013 compiler warning
698  ProgressCallbackCaller (const ProgressCallbackCaller& o) : callback (o.callback), data (o.data) { jassertfalse; }
699  ProgressCallbackCaller& operator= (const ProgressCallbackCaller&) { jassertfalse; return *this; }
700  };
701 
702  std::unique_ptr<ProgressCallbackCaller> callbackCaller
703  (progressCallback != nullptr ? new ProgressCallbackCaller (progressCallback, progressCallbackContext) : nullptr);
704 
705  if (headers.isNotEmpty())
706  wi->withExtraHeaders (headers);
707 
708  if (timeOutMs != 0)
709  wi->withConnectionTimeout (timeOutMs);
710 
711  if (httpRequestCmd.isNotEmpty())
712  wi->withCustomRequestCommand (httpRequestCmd);
713 
714  wi->withNumRedirectsToFollow (numRedirectsToFollow);
715 
716  bool success = wi->connect (callbackCaller.get());
717 
718  if (statusCode != nullptr)
719  *statusCode = wi->getStatusCode();
720 
721  if (responseHeaders != nullptr)
722  *responseHeaders = wi->getResponseHeaders();
723 
724  if (! success || wi->isError())
725  return nullptr;
726 
727  return wi.release();
728 }
729 
730 #if JUCE_ANDROID
731 OutputStream* juce_CreateContentURIOutputStream (const URL&);
732 #endif
733 
735 {
736  if (isLocalFile())
737  {
738  #if JUCE_IOS
739  // We may need to refresh the embedded bookmark.
740  return new iOSFileStreamWrapper<FileOutputStream> (const_cast<URL&> (*this));
741  #else
742  return new FileOutputStream (getLocalFile());
743  #endif
744  }
745 
746  #if JUCE_ANDROID
747  return juce_CreateContentURIOutputStream (*this);
748  #else
749  return nullptr;
750  #endif
751 }
752 
753 //==============================================================================
754 bool URL::readEntireBinaryStream (MemoryBlock& destData, bool usePostCommand) const
755 {
756  const std::unique_ptr<InputStream> in (isLocalFile() ? getLocalFile().createInputStream()
757  : static_cast<InputStream*> (createInputStream (usePostCommand)));
758 
759  if (in != nullptr)
760  {
761  in->readIntoMemoryBlock (destData);
762  return true;
763  }
764 
765  return false;
766 }
767 
768 String URL::readEntireTextStream (bool usePostCommand) const
769 {
770  const std::unique_ptr<InputStream> in (isLocalFile() ? getLocalFile().createInputStream()
771  : static_cast<InputStream*> (createInputStream (usePostCommand)));
772 
773  if (in != nullptr)
774  return in->readEntireStreamAsString();
775 
776  return {};
777 }
778 
779 XmlElement* URL::readEntireXmlStream (bool usePostCommand) const
780 {
781  return XmlDocument::parse (readEntireTextStream (usePostCommand));
782 }
783 
784 //==============================================================================
785 URL URL::withParameter (const String& parameterName,
786  const String& parameterValue) const
787 {
788  URL u (*this);
789  u.addParameter (parameterName, parameterValue);
790  return u;
791 }
792 
793 URL URL::withParameters (const StringPairArray& parametersToAdd) const
794 {
795  URL u (*this);
796 
797  for (int i = 0; i < parametersToAdd.size(); ++i)
798  u.addParameter (parametersToAdd.getAllKeys()[i],
799  parametersToAdd.getAllValues()[i]);
800 
801  return u;
802 }
803 
804 URL URL::withPOSTData (const String& newPostData) const
805 {
806  return withPOSTData (MemoryBlock (newPostData.toRawUTF8(), newPostData.getNumBytesAsUTF8()));
807 }
808 
809 URL URL::withPOSTData (const MemoryBlock& newPostData) const
810 {
811  URL u (*this);
812  u.postData = newPostData;
813  return u;
814 }
815 
816 URL::Upload::Upload (const String& param, const String& name,
817  const String& mime, const File& f, MemoryBlock* mb)
818  : parameterName (param), filename (name), mimeType (mime), file (f), data (mb)
819 {
820  jassert (mimeType.isNotEmpty()); // You need to supply a mime type!
821 }
822 
823 URL URL::withUpload (Upload* const f) const
824 {
825  URL u (*this);
826 
827  for (int i = u.filesToUpload.size(); --i >= 0;)
828  if (u.filesToUpload.getObjectPointerUnchecked(i)->parameterName == f->parameterName)
829  u.filesToUpload.remove (i);
830 
831  u.filesToUpload.add (f);
832  return u;
833 }
834 
835 URL URL::withFileToUpload (const String& parameterName, const File& fileToUpload,
836  const String& mimeType) const
837 {
838  return withUpload (new Upload (parameterName, fileToUpload.getFileName(),
839  mimeType, fileToUpload, nullptr));
840 }
841 
842 URL URL::withDataToUpload (const String& parameterName, const String& filename,
843  const MemoryBlock& fileContentToUpload, const String& mimeType) const
844 {
845  return withUpload (new Upload (parameterName, filename, mimeType, File(),
846  new MemoryBlock (fileContentToUpload)));
847 }
848 
849 //==============================================================================
851 {
852  auto result = s.replaceCharacter ('+', ' ');
853 
854  if (! result.containsChar ('%'))
855  return result;
856 
857  // We need to operate on the string as raw UTF8 chars, and then recombine them into unicode
858  // after all the replacements have been made, so that multi-byte chars are handled.
859  Array<char> utf8 (result.toRawUTF8(), (int) result.getNumBytesAsUTF8());
860 
861  for (int i = 0; i < utf8.size(); ++i)
862  {
863  if (utf8.getUnchecked(i) == '%')
864  {
865  auto hexDigit1 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 1]);
866  auto hexDigit2 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 2]);
867 
868  if (hexDigit1 >= 0 && hexDigit2 >= 0)
869  {
870  utf8.set (i, (char) ((hexDigit1 << 4) + hexDigit2));
871  utf8.removeRange (i + 1, 2);
872  }
873  }
874  }
875 
876  return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
877 }
878 
879 String URL::addEscapeChars (const String& s, bool isParameter, bool roundBracketsAreLegal)
880 {
881  String legalChars (isParameter ? "_-.~"
882  : ",$_-.*!'");
883 
884  if (roundBracketsAreLegal)
885  legalChars += "()";
886 
887  Array<char> utf8 (s.toRawUTF8(), (int) s.getNumBytesAsUTF8());
888 
889  for (int i = 0; i < utf8.size(); ++i)
890  {
891  auto c = utf8.getUnchecked(i);
892 
894  || legalChars.containsChar ((juce_wchar) c)))
895  {
896  utf8.set (i, '%');
897  utf8.insert (++i, "0123456789ABCDEF" [((uint8) c) >> 4]);
898  utf8.insert (++i, "0123456789ABCDEF" [c & 15]);
899  }
900  }
901 
902  return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
903 }
904 
905 //==============================================================================
907 {
908  auto u = toString (true);
909 
910  if (u.containsChar ('@') && ! u.containsChar (':'))
911  u = "mailto:" + u;
912 
913  return Process::openDocument (u, {});
914 }
915 
916 } // namespace juce
juce::Thread::startThread
void startThread()
Starts the thread running.
Definition: juce_Thread.cpp:122
juce::ReferenceCountedArray::size
int size() const noexcept
Returns the current number of objects in the array.
Definition: juce_ReferenceCountedArray.h:154
juce::URL::createInputStream
InputStream * createInputStream(bool doPostLikeRequest, OpenStreamProgressCallback *progressCallback=nullptr, void *progressCallbackContext=nullptr, String extraHeaders=String(), int connectionTimeOutMs=0, StringPairArray *responseHeaders=nullptr, int *statusCode=nullptr, int numRedirectsToFollow=5, String httpRequestCmd=String()) const
Attempts to open a stream that can read from this URL.
Definition: juce_URL.cpp:660
juce::URL::~URL
~URL()
Destructor.
Definition: juce_URL.cpp:238
juce::URL::withFileToUpload
URL withFileToUpload(const String &parameterName, const File &fileToUpload, const String &mimeType) const
Returns a copy of this URL, with a file-upload type parameter added to it.
Definition: juce_URL.cpp:835
juce::String::toRawUTF8
const char * toRawUTF8() const
Returns a pointer to a UTF-8 version of this string.
Definition: juce_String.cpp:2072
juce::File::getFileName
String getFileName() const
Returns the last section of the pathname.
Definition: juce_File.cpp:346
juce::URL::getSubPath
String getSubPath() const
Returns the path part of the URL.
Definition: juce_URL.cpp:350
juce::CharacterFunctions::getHexDigitValue
static int getHexDigitValue(juce_wchar digit) noexcept
Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit.
Definition: juce_CharacterFunctions.cpp:117
juce::String::containsChar
bool containsChar(juce_wchar character) const noexcept
Tests whether the string contains a particular character.
Definition: juce_String.cpp:1046
juce::String::containsIgnoreCase
bool containsIgnoreCase(StringRef text) const noexcept
Tests whether the string contains another substring.
Definition: juce_String.cpp:1051
juce::HeapBlock< char >
juce::String::lastIndexOfChar
int lastIndexOfChar(juce_wchar character) const noexcept
Searches for a character inside this string (working backwards from the end of the string).
Definition: juce_String.cpp:905
juce::File::getParentDirectory
File getParentDirectory() const
Returns the directory that contains this file or directory.
Definition: juce_File.cpp:340
juce::File::isRoot
bool isRoot() const
Checks whether the path of this file represents the root of a file system, irrespective of its existe...
Definition: juce_File.cpp:107
juce::Thread
Encapsulates a thread.
Definition: juce_Thread.h:46
juce::URL::getPort
int getPort() const
Attempts to read a port number from the URL.
Definition: juce_URL.cpp:409
juce::URL::readEntireXmlStream
XmlElement * readEntireXmlStream(bool usePostCommand=false) const
Tries to download the entire contents of this URL and parse it as XML.
Definition: juce_URL.cpp:779
juce::String::endsWithChar
bool endsWithChar(juce_wchar character) const noexcept
Tests whether the string ends with a particular character.
Definition: juce_String.cpp:1416
juce::File::createOutputStream
FileOutputStream * createOutputStream(size_t bufferSize=0x8000) const
Creates a stream to write to this file.
Definition: juce_File.cpp:719
juce::File::getSeparatorString
static StringRef getSeparatorString()
The system-specific file separator character, as a string.
juce::URL::isProbablyAnEmailAddress
static bool isProbablyAnEmailAddress(const String &possibleEmailAddress)
Takes a guess as to whether a string might be a valid email address.
Definition: juce_URL.cpp:517
juce::WebInputStream
An InputStream which can be used to read from a given url.
Definition: juce_WebInputStream.h:36
juce::Array::size
int size() const noexcept
Returns the current number of elements in the array.
Definition: juce_Array.h:219
juce::MemoryOutputStream
Writes data to an internal memory buffer, which grows as required.
Definition: juce_MemoryOutputStream.h:39
juce::File::getFullPathName
const String & getFullPathName() const noexcept
Returns the complete, absolute path of this file.
Definition: juce_File.h:153
juce::InputStream
The base class for streams that read data.
Definition: juce_InputStream.h:40
juce::URL::getScheme
String getScheme() const
Returns the scheme of the URL.
Definition: juce_URL.cpp:358
juce::String::getNumBytesAsUTF8
size_t getNumBytesAsUTF8() const noexcept
Returns the number of bytes required to represent this string as UTF8.
Definition: juce_String.cpp:2118
juce::URL
Represents a URL and has a bunch of useful functions to manipulate it.
Definition: juce_URL.h:41
juce::URL::withDataToUpload
URL withDataToUpload(const String &parameterName, const String &filename, const MemoryBlock &fileContentToUpload, const String &mimeType) const
Returns a copy of this URL, with a file-upload type parameter added to it.
Definition: juce_URL.cpp:842
juce::URL::DownloadTask::Listener::finished
virtual void finished(URL::DownloadTask *task, bool success)=0
Called when the download has finished.
juce::Thread::threadShouldExit
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
Definition: juce_Thread.cpp:182
juce::Array::removeRange
void removeRange(int startIndex, int numberToRemove)
Removes a range of elements from the array.
Definition: juce_Array.h:873
juce::StringArray::fromTokens
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Returns an array containing the tokens in a given string.
Definition: juce_StringArray.cpp:386
juce::URL::toString
String toString(bool includeGetParameters) const
Returns a string version of the URL.
Definition: juce_URL.cpp:326
juce::URL::launchInDefaultBrowser
bool launchInDefaultBrowser() const
Tries to launch the system's default browser to open the URL.
Definition: juce_URL.cpp:906
juce::Array
Holds a resizable array of primitive or copy-by-value objects.
Definition: juce_Array.h:59
juce::URL::withParameter
URL withParameter(const String &parameterName, const String &parameterValue) const
Returns a copy of this URL, with a GET or POST parameter added to the end.
Definition: juce_URL.cpp:785
juce::String::toHexString
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
Definition: juce_String.h:1055
juce::String::startsWithIgnoreCase
bool startsWithIgnoreCase(StringRef text) const noexcept
Tests whether the string begins with another string.
Definition: juce_String.cpp:1404
juce::StringPairArray::getAllKeys
const StringArray & getAllKeys() const noexcept
Returns a list of all keys in the array.
Definition: juce_StringPairArray.h:91
juce::URL::DownloadTask::Listener
Used to receive callbacks for download progress.
Definition: juce_URL.h:360
juce::OutputStream::flush
virtual void flush()=0
If the stream is using a buffer, this will ensure it gets written out to the destination.
juce::XmlElement
Used to build a tree of elements representing an XML document.
Definition: juce_XmlElement.h:141
juce::WebInputStream::Listener
Used to receive callbacks for data send progress.
Definition: juce_WebInputStream.h:40
juce::URL::getDomain
String getDomain() const
Returns just the domain part of the URL.
Definition: juce_URL.cpp:345
juce::OutputStream
The base class for streams that write data to some kind of destination.
Definition: juce_OutputStream.h:41
juce::String::startsWith
bool startsWith(StringRef text) const noexcept
Tests whether the string begins with another string.
Definition: juce_String.cpp:1399
juce::URL::getFileName
String getFileName() const
Returns the file name.
juce::MemoryBlock::getSize
size_t getSize() const noexcept
Returns the block's current allocated size, in bytes.
Definition: juce_MemoryBlock.h:111
juce::File
Represents a local file or directory.
Definition: juce_File.h:44
juce::Thread::signalThreadShouldExit
void signalThreadShouldExit()
Sets a flag to tell the thread it should stop.
Definition: juce_Thread.cpp:176
juce::String::replaceCharacter
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
Returns a string with all occurrences of a character replaced with a different one.
Definition: juce_String.cpp:1350
juce::File::deleteFile
bool deleteFile() const
Deletes a file.
juce::StringArray::size
int size() const noexcept
Returns the number of strings in the array.
Definition: juce_StringArray.h:139
juce::URL::OpenStreamProgressCallback
bool(void *context, int bytesSent, int totalBytes) OpenStreamProgressCallback
This callback function can be used by the createInputStream() method.
Definition: juce_URL.h:291
juce::URL::DownloadTask::~DownloadTask
virtual ~DownloadTask()
Releases the resources of the download task, unregisters the listener and cancels the download if nec...
Definition: juce_URL.cpp:135
juce::StringPairArray
A container for holding a set of strings which are keyed by another string.
Definition: juce_StringPairArray.h:38
juce::URL::removeEscapeChars
static String removeEscapeChars(const String &stringToRemoveEscapeCharsFrom)
Replaces any escape character sequences in a string with their original character codes.
Definition: juce_URL.cpp:850
juce::String::upToFirstOccurrenceOf
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Returns the start of this string, up to the first occurrence of a substring.
Definition: juce_String.cpp:1591
juce::URL::DownloadTask::Listener::progress
virtual void progress(URL::DownloadTask *task, int64 bytesDownloaded, int64 totalLength)
Called periodically by the OS to indicate download progress.
Definition: juce_URL.cpp:109
juce::URL::withPOSTData
URL withPOSTData(const String &postData) const
Returns a copy of this URL, with a block of data to send as the POST data.
Definition: juce_URL.cpp:804
juce::URL::getLocalFile
File getLocalFile() const
Returns the file path of the local file to which this URL refers to.
juce::Array::getUnchecked
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
Definition: juce_Array.h:256
juce::URL::addEscapeChars
static String addEscapeChars(const String &stringToAddEscapeCharsTo, bool isParameter, bool roundBracketsAreLegal=true)
Adds escape sequences to a string to encode any characters that aren't legal in a URL.
Definition: juce_URL.cpp:879
juce::URL::isEmpty
bool isEmpty() const noexcept
Returns true if the URL is an empty string.
Definition: juce_URL.cpp:334
juce::URL::createWithoutParsing
static URL createWithoutParsing(const String &url)
Returns a URL without attempting to remove any embedded parameters from the string.
Definition: juce_URL.cpp:240
juce::URL::createOutputStream
OutputStream * createOutputStream() const
Attempts to open an output stream to a URL for writing.
Definition: juce_URL.cpp:734
juce::String::length
int length() const noexcept
Returns the number of characters in the string.
Definition: juce_String.cpp:518
juce::File::createInputStream
FileInputStream * createInputStream() const
Creates a stream to read from this file.
Definition: juce_File.cpp:709
juce::CharacterFunctions::isLetterOrDigit
static bool isLetterOrDigit(char character) noexcept
Checks whether a character is alphabetic or numeric.
Definition: juce_CharacterFunctions.cpp:95
juce::URL::isWellFormed
bool isWellFormed() const
True if it seems to be valid.
Definition: juce_URL.cpp:339
juce::Random::getSystemRandom
static Random & getSystemRandom() noexcept
The overhead of creating a new Random object is fairly small, but if you want to avoid it,...
Definition: juce_Random.cpp:71
juce::URL::withNewSubPath
URL withNewSubPath(const String &newPath) const
Returns a new version of this URL with a different sub-path.
Definition: juce_URL.cpp:423
juce::URL::operator==
bool operator==(const URL &) const
Compares two URLs.
Definition: juce_URL.cpp:245
juce::URL::readEntireTextStream
String readEntireTextStream(bool usePostCommand=false) const
Tries to download the entire contents of this URL as a string.
Definition: juce_URL.cpp:768
juce::String::isNotEmpty
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
Definition: juce_String.h:306
juce::Array::getRawDataPointer
ElementType * getRawDataPointer() noexcept
Returns a pointer to the actual array data.
Definition: juce_Array.h:300
juce::iOSFileStreamWrapperFlush
Definition: juce_URL.cpp:562
juce::URL::readEntireBinaryStream
bool readEntireBinaryStream(MemoryBlock &destData, bool usePostCommand=false) const
Tries to download the entire contents of this URL into a binary data block.
Definition: juce_URL.cpp:754
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::FallbackDownloadTask
Definition: juce_URL.cpp:26
juce::XmlDocument::parse
static XmlElement * parse(const File &file)
A handy static method that parses a file.
Definition: juce_XmlDocument.cpp:31
juce::HeapBlock::get
ElementType * get() const noexcept
Returns a raw pointer to the allocated data.
Definition: juce_HeapBlock.h:192
juce::String::substring
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
Definition: juce_String.cpp:1504
juce::Thread::waitForThreadToExit
bool waitForThreadToExit(int timeOutMilliseconds) const
Waits for the thread to stop.
Definition: juce_Thread.cpp:195
juce::URL::URL
URL() noexcept
Creates an empty URL.
Definition: juce_URL.cpp:138
juce::Thread::Thread
Thread(const String &threadName, size_t threadStackSize=0)
Creates a thread.
Definition: juce_Thread.cpp:26
juce::URL::DownloadTask
Represents a download task.
Definition: juce_URL.h:356
juce::StringArray::add
void add(String stringToAdd)
Appends a string at the end of the array.
Definition: juce_StringArray.cpp:135
juce::FallbackDownloadTask::run
void run() override
Must be implemented to perform the thread's actual code.
Definition: juce_URL.cpp:58
juce::Array::set
void set(int indexToChange, ParameterType newValue)
Replaces an element with a new value.
Definition: juce_Array.h:499
juce::URL::getChildURL
URL getChildURL(const String &subPath) const
Returns a new URL that refers to a sub-path relative to this one.
Definition: juce_URL.cpp:436
juce::iOSFileStreamWrapper
Definition: juce_URL.cpp:566
juce::Process::openDocument
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String &parameters)
Tries to launch the OS's default reader application for a given file or URL.
juce::String::startsWithChar
bool startsWithChar(juce_wchar character) const noexcept
Tests whether the string begins with a particular character.
Definition: juce_String.cpp:1409
juce::String::replace
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Replaces all occurrences of a substring with another string.
Definition: juce_String.cpp:1285
juce::URL::isLocalFile
bool isLocalFile() const
Returns true if this URL refers to a local file.
juce::String::fromFirstOccurrenceOf
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from a given substring.
Definition: juce_String.cpp:1571
juce::FileOutputStream
An output stream that writes into a local file.
Definition: juce_FileOutputStream.h:38
juce::StringPairArray::size
int size() const noexcept
Returns the number of strings in the array.
Definition: juce_StringPairArray.h:97
juce::StringPairArray::getAllValues
const StringArray & getAllValues() const noexcept
Returns a list of all values in the array.
Definition: juce_StringPairArray.h:94
juce::URL::withParameters
URL withParameters(const StringPairArray &parametersToAdd) const
Returns a copy of this URL, with a set of GET or POST parameters added.
Definition: juce_URL.cpp:793
juce::String::indexOfChar
int indexOfChar(juce_wchar characterToLookFor) const noexcept
Searches for a character inside this string.
Definition: juce_String.cpp:880
juce::String::fromUTF8
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
Definition: juce_String.cpp:2123
juce::URL::withNewDomainAndPath
URL withNewDomainAndPath(const String &newFullPath) const
Returns a new version of this URL with a different domain and path.
Definition: juce_URL.cpp:416
juce::Array::insert
void insert(int indexToInsertAt, ParameterType newElement)
Inserts a new element into the array at a given position.
Definition: juce_Array.h:419
juce::URL::isProbablyAWebsiteURL
static bool isProbablyAWebsiteURL(const String &possibleURL)
Takes a guess as to whether a string might be a valid website address.
Definition: juce_URL.cpp:499
juce::String::fromLastOccurrenceOf
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from the last occurrence of a given substring.
Definition: juce_String.cpp:1581
juce::MemoryBlock
A class to hold a resizable block of raw data.
Definition: juce_MemoryBlock.h:36