-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Break out base64 test and url test methods to util classes
- Loading branch information
1 parent
944db4a
commit 4d64736
Showing
5 changed files
with
238 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/Base64Util.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package org.hl7.fhir.validation.instance.utils; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.nio.charset.StandardCharsets; | ||
import org.apache.commons.codec.binary.Base64InputStream; | ||
|
||
import org.hl7.fhir.utilities.Utilities; | ||
|
||
public class Base64Util { | ||
/** | ||
* Technically this is not bulletproof as some invalid base64 won't be caught, | ||
* but I think it's good enough. The original code used Java8 Base64 decoder | ||
* but I've replaced it with a regex for 2 reasons: | ||
* 1. This code will run on any version of Java | ||
* 2. This code doesn't actually decode, which is much easier on memory use for big payloads | ||
*/ | ||
public static boolean isValidBase64(String theEncoded) { | ||
if (theEncoded == null) { | ||
return false; | ||
} | ||
int charCount = 0; | ||
boolean ok = true; | ||
for (int i = 0; i < theEncoded.length(); i++) { | ||
char nextChar = theEncoded.charAt(i); | ||
if (Utilities.isWhitespace(nextChar)) { | ||
continue; | ||
} | ||
if (Character.isLetterOrDigit(nextChar)) { | ||
charCount++; | ||
} | ||
if (nextChar == '/' || nextChar == '=' || nextChar == '+') { | ||
charCount++; | ||
} | ||
} | ||
|
||
if (charCount > 0 && charCount % 4 != 0) { | ||
ok = false; | ||
} | ||
return ok; | ||
} | ||
|
||
public static boolean base64HasWhitespace(String theEncoded) { | ||
if (theEncoded == null) { | ||
return false; | ||
} | ||
for (int i = 0; i < theEncoded.length(); i++) { | ||
char nextChar = theEncoded.charAt(i); | ||
if (Utilities.isWhitespace(nextChar)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
public static int countBase64DecodedBytes(String theEncoded) { | ||
Base64InputStream inputStream = new Base64InputStream(new ByteArrayInputStream(theEncoded.getBytes(StandardCharsets.UTF_8))); | ||
try { | ||
try { | ||
for (int counter = 0; ; counter++) { | ||
if (inputStream.read() == -1) { | ||
return counter; | ||
} | ||
} | ||
} finally { | ||
inputStream.close(); | ||
} | ||
} catch (IOException e) { | ||
throw new IllegalStateException(e); // should not happen | ||
} | ||
} | ||
|
||
} |
57 changes: 57 additions & 0 deletions
57
org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/utils/UrlUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package org.hl7.fhir.validation.instance.utils; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import org.hl7.fhir.r5.context.IWorkerContext; | ||
import org.hl7.fhir.utilities.i18n.I18nConstants; | ||
import org.hl7.fhir.utilities.Utilities; | ||
import org.hl7.fhir.validation.instance.utils.Base64Util; | ||
|
||
public class UrlUtil { | ||
public static String checkValidUrl(String value, IWorkerContext context) { | ||
if (value == null) { | ||
return null; | ||
} | ||
if (Utilities.noString(value)) { | ||
return context.formatMessage(I18nConstants.XHTML_URL_EMPTY); | ||
} | ||
|
||
if (value.startsWith("data:")) { | ||
String[] p = value.substring(5).split("\\,"); | ||
if (p.length < 2) { | ||
return context.formatMessage(I18nConstants.XHTML_URL_DATA_NO_DATA, value); | ||
} else if (p.length > 2) { | ||
return context.formatMessage(I18nConstants.XHTML_URL_DATA_DATA_INVALID_COMMA, value); | ||
} else if (p[0].endsWith(";base64") && !Base64Util.isValidBase64(p[1])) { | ||
return context.formatMessage(I18nConstants.XHTML_URL_DATA_DATA_INVALID, value); | ||
} else { | ||
if (p[0].startsWith(" ")) { | ||
p[0] = Utilities.trimWS(p[0]); | ||
} | ||
String mimetype = (p[0].endsWith(";base64")) ? p[0].substring(0, p[0].lastIndexOf(";")) : p[0]; | ||
if (!mimetype.trim().isEmpty()) { | ||
String mMsg = MimeTypeUtil.checkValidMimeType(mimetype); | ||
if (mMsg != null) { | ||
return context.formatMessage(I18nConstants.XHTML_URL_DATA_MIMETYPE, value, mMsg); | ||
} | ||
} | ||
} | ||
return null; | ||
} else { | ||
Set<Character> invalidChars = new HashSet<>(); | ||
int c = 0; | ||
for (char ch : value.toCharArray()) { | ||
if (!(Character.isDigit(ch) || Character.isAlphabetic(ch) || Utilities.existsInList(ch, ';', '?', ':', '@', '&', '=', '+', '$', '.', ',', '/', '%', '-', '_', '~', '#', '[', ']', '!', '\'', '(', ')', '*', '|' ))) { | ||
c++; | ||
invalidChars.add(ch); | ||
} | ||
} | ||
if (invalidChars.isEmpty()) { | ||
return null; | ||
} else { | ||
return context.formatMessagePlural(c, I18nConstants.XHTML_URL_INVALID_CHARS, invalidChars.toString()); | ||
} | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
....fhir.validation/src/test/java/org/hl7/fhir/validation/instance/utils/Base64UtilTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package org.hl7.fhir.validation.instance.utils; | ||
|
||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.ValueSource; | ||
import org.junit.jupiter.params.provider.CsvSource; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
public class Base64UtilTest { | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = { | ||
"AAAA", | ||
"AAAABBBB", | ||
"AA AA BB BB ", | ||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 /+====" | ||
}) | ||
public void testValidBase64(String base64) { | ||
assertTrue(Base64Util.isValidBase64(base64)); | ||
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = { | ||
"A==", // Improperly padded | ||
"A(B=", // Invalid character in the defualt encoding | ||
}) | ||
public void testInvalidBase64(String base64) { | ||
assertFalse(Base64Util.isValidBase64(base64)); | ||
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = { | ||
"AA AA", | ||
"AA AA", | ||
"AAAA ", | ||
"AA\nAA", | ||
}) | ||
public void testBase64WithWhitespace(String base64) { | ||
assertTrue(Base64Util.base64HasWhitespace(base64)); | ||
} | ||
|
||
public void testBase64WithoutWhitespace(String base64) { | ||
assertFalse(Base64Util.base64HasWhitespace("AAAA")); | ||
} | ||
|
||
@ParameterizedTest | ||
@CsvSource({ | ||
"AAAA, 3", | ||
"AAAABBBB, 6", | ||
"AAA=, 2", | ||
}) | ||
public void testValidBase64(String base64, int length) { | ||
assertEquals(Base64Util.countBase64DecodedBytes(base64), length); | ||
} | ||
|
||
} |
Oops, something went wrong.