001package org.hl7.fhir.utilities; 002 003import java.io.DataOutputStream; 004import java.io.IOException; 005import java.net.HttpURLConnection; 006import java.net.URL; 007import java.net.URLDecoder; 008import java.nio.charset.StandardCharsets; 009import java.util.ArrayList; 010import java.util.Base64; 011import java.util.HashMap; 012import java.util.List; 013import java.util.Map; 014 015import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; 016import org.hl7.fhir.utilities.SimpleHTTPClient.Header; 017import org.hl7.fhir.utilities.npm.SSLCertTruster; 018 019public class SimpleHTTPClient { 020 021 public class Header { 022 private String name; 023 private String value; 024 public Header(String name, String value) { 025 super(); 026 this.name = name; 027 this.value = value; 028 } 029 public String getName() { 030 return name; 031 } 032 public String getValue() { 033 return value; 034 } 035 } 036 037 private static final int MAX_REDIRECTS = 5; 038 039 public class HTTPResult { 040 private int code; 041 private String contentType; 042 private byte[] content; 043 private String source; 044 045 046 public HTTPResult(String source, int code, String contentType, byte[] content) { 047 super(); 048 this.source = source; 049 this.code = code; 050 this.contentType = contentType; 051 this.content = content; 052 } 053 054 public int getCode() { 055 return code; 056 } 057 public String getContentType() { 058 return contentType; 059 } 060 public byte[] getContent() { 061 return content; 062 } 063 064 public String getSource() { 065 return source; 066 } 067 068 public void checkThrowException() throws IOException { 069 if (code >= 300) { 070 throw new IOException("Invalid HTTP response "+code+" from "+source); 071 } 072 } 073 } 074 075 private List<Header> headers = new ArrayList<>(); 076 private String username; 077 private String password; 078 079 public void addHeader(String name, String value) { 080 headers.add(new Header(name, value)); 081 } 082 083 public String getUsername() { 084 return username; 085 } 086 087 public void setUsername(String username) { 088 this.username = username; 089 } 090 091 public String getPassword() { 092 return password; 093 } 094 095 public void setPassword(String password) { 096 this.password = password; 097 } 098 099 100 private boolean trustAll = false; 101 102 public void trustAllhosts() { 103 trustAll = true; 104 SSLCertTruster.trustAllHosts(); 105 } 106 107 public HTTPResult get(String url) throws IOException { 108 return get(url, null); 109 } 110 111 public HTTPResult get(String url, String accept) throws IOException { 112 URL u = new URL(url); 113// boolean isSSL = url.startsWith("https://"); 114 115 // handling redirects - setInstanceFollowRedirects(true) doesn't handle crossing http to https 116 117 Map<String, Integer> visited = new HashMap<>(); 118 HttpURLConnection c = null; 119 boolean done = false; 120 121 while (!done) { 122 int times = visited.compute(url, (key, count) -> count == null ? 1 : count + 1); 123 if (times > MAX_REDIRECTS) 124 throw new IOException("Stuck in redirect loop"); 125 126 u = new URL(url); 127 c = (HttpURLConnection) u.openConnection(); 128 c.setRequestMethod("GET"); 129 c.setRequestProperty("Accept", accept); 130 setHeaders(c); 131 c.setInstanceFollowRedirects(false); 132 if (trustAll && url.startsWith("https://")) { 133 ((javax.net.ssl.HttpsURLConnection) c).setHostnameVerifier(SSLCertTruster.DO_NOT_VERIFY); 134 } 135 136 switch (c.getResponseCode()) { 137 case HttpURLConnection.HTTP_MOVED_PERM: 138 case HttpURLConnection.HTTP_MOVED_TEMP: 139 String location = c.getHeaderField("Location"); 140 location = URLDecoder.decode(location, "UTF-8"); 141 URL base = new URL(url); 142 URL next = new URL(base, location); // Deal with relative URLs 143 url = next.toExternalForm(); 144 continue; 145 default: 146 done = true; 147 } 148 } 149 150 return new HTTPResult(url, c.getResponseCode(), c.getRequestProperty("Content-Type"), TextFile.streamToBytes(c.getInputStream())); 151 } 152 153 private void setHeaders(HttpURLConnection c) { 154 for (Header h : headers) { 155 c.setRequestProperty(h.getName(), h.getValue()); 156 } 157 c.setConnectTimeout(15000); 158 c.setReadTimeout(15000); 159 if (username != null) { 160 String auth = username+":"+password; 161 byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8)); 162 String authHeaderValue = "Basic " + new String(encodedAuth); 163 c.setRequestProperty("Authorization", authHeaderValue); 164 } 165 } 166 167 public HTTPResult post(String url, String contentType, byte[] content, String accept) throws IOException { 168 URL u = new URL(url); 169 HttpURLConnection c = (HttpURLConnection) u.openConnection(); 170 c.setDoOutput(true); 171 c.setDoInput(true); 172 c.setRequestMethod("POST"); 173 c.setRequestProperty("Content-type", contentType); 174 if (accept != null) { 175 c.setRequestProperty("Accept", accept); 176 } 177 setHeaders(c); 178 c.getOutputStream().write(content); 179 c.getOutputStream().close(); 180 return new HTTPResult(url, c.getResponseCode(), c.getRequestProperty("Content-Type"), TextFile.streamToBytes(c.getInputStream())); 181 } 182 183 184 public HTTPResult put(String url, String contentType, byte[] content, String accept) throws IOException { 185 URL u = new URL(url); 186 HttpURLConnection c = (HttpURLConnection) u.openConnection(); 187 c.setDoOutput(true); 188 c.setDoInput(true); 189 c.setRequestMethod("PUT"); 190 c.setRequestProperty("Content-type", contentType); 191 if (accept != null) { 192 c.setRequestProperty("Accept", accept); 193 } 194 setHeaders(c); 195 c.getOutputStream().write(content); 196 c.getOutputStream().close(); 197 return new HTTPResult(url, c.getResponseCode(), c.getRequestProperty("Content-Type"), TextFile.streamToBytes(c.getInputStream())); 198 } 199 200 201}