From 3c6639b4f69cff65a2fe3ad10cda0bc547a9ac9d Mon Sep 17 00:00:00 2001 From: xhh Date: Mon, 11 Jan 2016 22:13:07 +0800 Subject: [PATCH 1/3] Remove path delimiters from downloading filename --- .../Java/libraries/okhttp-gson/ApiClient.mustache | 5 +++-- .../src/main/java/io/swagger/client/ApiClient.java | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache index 8c0880bf217..5f68f794e68 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache @@ -724,8 +724,9 @@ public class ApiClient { // Get filename from the Content-Disposition header. Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); Matcher matcher = pattern.matcher(contentDisposition); - if (matcher.find()) - filename = matcher.group(1); + if (matcher.find()) { + filename = matcher.group(1).replaceAll(".*[/\\\\]", ""); + } } String prefix = null; diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java index 7fb4cc49bf3..3c9d18d5fc7 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java @@ -141,8 +141,8 @@ public class ApiClient { // Setup authentications (key: authentication name, value: authentication). authentications = new HashMap(); - authentications.put("api_key", new ApiKeyAuth("header", "api_key")); authentications.put("petstore_auth", new OAuth()); + authentications.put("api_key", new ApiKeyAuth("header", "api_key")); // Prevent the authentications from being modified. authentications = Collections.unmodifiableMap(authentications); } @@ -723,8 +723,9 @@ public class ApiClient { // Get filename from the Content-Disposition header. Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); Matcher matcher = pattern.matcher(contentDisposition); - if (matcher.find()) - filename = matcher.group(1); + if (matcher.find()) { + filename = matcher.group(1).replaceAll(".*[/\\\\]", ""); + } } String prefix = null; From ef8d2fd7661378151e2e63e4e329fecad1aea172 Mon Sep 17 00:00:00 2001 From: xhh Date: Tue, 12 Jan 2016 11:57:24 +0800 Subject: [PATCH 2/3] Ruby: IO improvements on file downloading - Use `File.basename` to sanitize the filename got from response header - Write to the `Tempfile` directly and return it - Set file encoding according to the response body's encoding See #1848 --- .../main/resources/ruby/api_client.mustache | 25 +++++++++++-------- .../petstore/ruby/lib/petstore/api_client.rb | 25 +++++++++++-------- samples/client/petstore/ruby/petstore.gemspec | 13 +++++----- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache index 54854efe332..d61627fb26e 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache @@ -170,23 +170,28 @@ module {{moduleName}} # from the "Content-Disposition" header if provided, otherwise a random filename. # # @see Configuration#temp_folder_path - # @return [File] the file downloaded + # @return [Tempfile] the file downloaded def download_file(response) - tmp_file = Tempfile.new '', @config.temp_folder_path content_disposition = response.headers['Content-Disposition'] if content_disposition filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1] - path = File.join File.dirname(tmp_file), filename + prefix = File.basename(filename) else - path = tmp_file.path + prefix = 'download-' end - # close and delete temp file - tmp_file.close! + prefix = prefix + '-' unless prefix.end_with?('-') - File.open(path, 'w') { |file| file.write(response.body) } - @config.logger.info "File written to #{path}. Please move the file to a proper folder "\ - "for further processing and delete the temp afterwards" - File.new(path) + tempfile = nil + encoding = response.body.encoding + Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding) do |file| + file.write(response.body) + tempfile = file + end + @config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\ + "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\ + "will be deleted automatically with GC. It's also recommended to delete the temp file "\ + "explicitly with `tempfile.delete`" + tempfile end def build_request_url(path) diff --git a/samples/client/petstore/ruby/lib/petstore/api_client.rb b/samples/client/petstore/ruby/lib/petstore/api_client.rb index 53be21db3b0..2706bbdb325 100644 --- a/samples/client/petstore/ruby/lib/petstore/api_client.rb +++ b/samples/client/petstore/ruby/lib/petstore/api_client.rb @@ -170,23 +170,28 @@ module Petstore # from the "Content-Disposition" header if provided, otherwise a random filename. # # @see Configuration#temp_folder_path - # @return [File] the file downloaded + # @return [Tempfile] the file downloaded def download_file(response) - tmp_file = Tempfile.new '', @config.temp_folder_path content_disposition = response.headers['Content-Disposition'] if content_disposition filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1] - path = File.join File.dirname(tmp_file), filename + prefix = File.basename(filename) else - path = tmp_file.path + prefix = 'download-' end - # close and delete temp file - tmp_file.close! + prefix = prefix + '-' unless prefix.end_with?('-') - File.open(path, 'w') { |file| file.write(response.body) } - @config.logger.info "File written to #{path}. Please move the file to a proper folder "\ - "for further processing and delete the temp afterwards" - File.new(path) + tempfile = nil + encoding = response.body.encoding + Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding) do |file| + file.write(response.body) + tempfile = file + end + @config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\ + "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\ + "will be deleted automatically with GC. It's also recommended to delete the temp file "\ + "explicitly with `tempfile.delete`" + tempfile end def build_request_url(path) diff --git a/samples/client/petstore/ruby/petstore.gemspec b/samples/client/petstore/ruby/petstore.gemspec index df8a6df24d0..d9bb07c1902 100644 --- a/samples/client/petstore/ruby/petstore.gemspec +++ b/samples/client/petstore/ruby/petstore.gemspec @@ -6,12 +6,13 @@ Gem::Specification.new do |s| s.name = "petstore" s.version = Petstore::VERSION s.platform = Gem::Platform::RUBY - s.authors = ["Zeke Sikelianos", "Tony Tam"] - s.email = ["zeke@wordnik.com", "fehguy@gmail.com"] - s.homepage = "http://swagger.io" - s.summary = %q{A ruby wrapper for the swagger APIs} - s.description = %q{This gem maps to a swagger API} - s.license = "Apache-2.0" + s.authors = [""] + s.email = [""] + s.homepage = "" + s.summary = "" + s.description = "" + s.license = "" + s.add_runtime_dependency 'typhoeus', '~> 0.2', '>= 0.2.1' s.add_runtime_dependency 'json', '~> 1.4', '>= 1.4.6' From 521ba9924b1f5218fb632605aca11b14b73cfd0f Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 14 Jan 2016 23:06:30 +0800 Subject: [PATCH 3/3] Add a method to sanitize filename, add test cases --- .../libraries/okhttp-gson/ApiClient.mustache | 13 ++++++++++++- .../src/main/resources/ruby/api_client.mustache | 11 ++++++++++- .../main/java/io/swagger/client/ApiClient.java | 13 ++++++++++++- .../java/io/swagger/client/ApiClientTest.java | 13 +++++++++++++ .../petstore/ruby/lib/petstore/api_client.rb | 11 ++++++++++- .../client/petstore/ruby/spec/api_client_spec.rb | 16 ++++++++++++++++ 6 files changed, 73 insertions(+), 4 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache index 5f68f794e68..7d468373105 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache @@ -567,6 +567,17 @@ public class ApiClient { return params; } + /** + * Sanitize filename by removing path. + * e.g. ../../sun.gif becomes sun.gif + * + * @param filename The filename to be sanitized + * @return The sanitized filename + */ + public String sanitizeFilename(String filename) { + return filename.replaceAll(".*[/\\\\]", ""); + } + /** * Check if the given MIME is a JSON MIME. * JSON MIME examples: @@ -725,7 +736,7 @@ public class ApiClient { Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); Matcher matcher = pattern.matcher(contentDisposition); if (matcher.find()) { - filename = matcher.group(1).replaceAll(".*[/\\\\]", ""); + filename = sanitizeFilename(matcher.group(1)); } } diff --git a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache index d61627fb26e..e9c2160450e 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache @@ -175,7 +175,7 @@ module {{moduleName}} content_disposition = response.headers['Content-Disposition'] if content_disposition filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1] - prefix = File.basename(filename) + prefix = sanitize_filename(filename) else prefix = 'download-' end @@ -194,6 +194,15 @@ module {{moduleName}} tempfile end + # Sanitize filename by removing path. + # e.g. ../../sun.gif becomes sun.gif + # + # @param [String] filename the filename to be sanitized + # @return [String] the sanitized filename + def sanitize_filename(filename) + filename.gsub /.*[\/\\]/, '' + end + def build_request_url(path) # Add leading and trailing slashes to path path = "/#{path}".gsub(/\/+/, '/') diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java index 3c9d18d5fc7..2c2f1e5fd52 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java @@ -566,6 +566,17 @@ public class ApiClient { return params; } + /** + * Sanitize filename by removing path. + * e.g. ../../sun.gif becomes sun.gif + * + * @param filename The filename to be sanitized + * @return The sanitized filename + */ + public String sanitizeFilename(String filename) { + return filename.replaceAll(".*[/\\\\]", ""); + } + /** * Check if the given MIME is a JSON MIME. * JSON MIME examples: @@ -724,7 +735,7 @@ public class ApiClient { Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); Matcher matcher = pattern.matcher(contentDisposition); if (matcher.find()) { - filename = matcher.group(1).replaceAll(".*[/\\\\]", ""); + filename = sanitizeFilename(matcher.group(1)); } } diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java index ba143470c9a..6a116a89393 100644 --- a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java @@ -276,4 +276,17 @@ public class ApiClientTest { assertEquals(values.size(), pairValueSplit.length); } } + + @Test + public void testSanitizeFilename() { + assertEquals("sun", apiClient.sanitizeFilename("sun")); + assertEquals("sun.gif", apiClient.sanitizeFilename("sun.gif")); + assertEquals("sun.gif", apiClient.sanitizeFilename("../sun.gif")); + assertEquals("sun.gif", apiClient.sanitizeFilename("/var/tmp/sun.gif")); + assertEquals("sun.gif", apiClient.sanitizeFilename("./sun.gif")); + assertEquals("sun.gif", apiClient.sanitizeFilename("..\\sun.gif")); + assertEquals("sun.gif", apiClient.sanitizeFilename("\\var\\tmp\\sun.gif")); + assertEquals("sun.gif", apiClient.sanitizeFilename("c:\\var\\tmp\\sun.gif")); + assertEquals("sun.gif", apiClient.sanitizeFilename(".\\sun.gif")); + } } diff --git a/samples/client/petstore/ruby/lib/petstore/api_client.rb b/samples/client/petstore/ruby/lib/petstore/api_client.rb index 2706bbdb325..a38f5aa81d7 100644 --- a/samples/client/petstore/ruby/lib/petstore/api_client.rb +++ b/samples/client/petstore/ruby/lib/petstore/api_client.rb @@ -175,7 +175,7 @@ module Petstore content_disposition = response.headers['Content-Disposition'] if content_disposition filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1] - prefix = File.basename(filename) + prefix = sanitize_filename(filename) else prefix = 'download-' end @@ -194,6 +194,15 @@ module Petstore tempfile end + # Sanitize filename by removing path. + # e.g. ../../sun.gif becomes sun.gif + # + # @param [String] filename the filename to be sanitized + # @return [String] the sanitized filename + def sanitize_filename(filename) + filename.gsub /.*[\/\\]/, '' + end + def build_request_url(path) # Add leading and trailing slashes to path path = "/#{path}".gsub(/\/+/, '/') diff --git a/samples/client/petstore/ruby/spec/api_client_spec.rb b/samples/client/petstore/ruby/spec/api_client_spec.rb index 347b9876cf7..a02d4a2d760 100644 --- a/samples/client/petstore/ruby/spec/api_client_spec.rb +++ b/samples/client/petstore/ruby/spec/api_client_spec.rb @@ -258,4 +258,20 @@ describe Petstore::ApiClient do end end + describe "#sanitize_filename" do + let(:api_client) { Petstore::ApiClient.new } + + it "works" do + api_client.sanitize_filename('sun').should == 'sun' + api_client.sanitize_filename('sun.gif').should == 'sun.gif' + api_client.sanitize_filename('../sun.gif').should == 'sun.gif' + api_client.sanitize_filename('/var/tmp/sun.gif').should == 'sun.gif' + api_client.sanitize_filename('./sun.gif').should == 'sun.gif' + api_client.sanitize_filename('..\sun.gif').should == 'sun.gif' + api_client.sanitize_filename('\var\tmp\sun.gif').should == 'sun.gif' + api_client.sanitize_filename('c:\var\tmp\sun.gif').should == 'sun.gif' + api_client.sanitize_filename('.\sun.gif').should == 'sun.gif' + end + end + end