Improve URL validation + fix NPE in Measure validation
This commit is contained in:
parent
549abaa799
commit
4d30314a3d
|
@ -37,6 +37,7 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
@ -114,90 +115,17 @@ public class ProfileComparer implements ProfileKnowledgeProvider {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.keygen = keygen;
|
this.keygen = keygen;
|
||||||
this.folder = folder;
|
this.folder = folder;
|
||||||
if (!new File(Utilities.path(folder, "conparison-zip-marker.bin")).exists()) {
|
for (Entry<String, byte[]> e : context.getBinaries().entrySet()) {
|
||||||
String f = Utilities.path(folder, "comparison.zip");
|
TextFile.bytesToFile(e.getValue(), Utilities.path(folder, e.getKey()));
|
||||||
download("http://www.fhir.org/archive/comparison.zip", f);
|
|
||||||
unzip(f, folder);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void download(String address, String filename) throws IOException {
|
|
||||||
// System.out.print("Download "+address+" to "+filename);
|
|
||||||
URL url = new URL(address);
|
|
||||||
URLConnection c = url.openConnection();
|
|
||||||
InputStream s = c.getInputStream();
|
|
||||||
FileOutputStream f = new FileOutputStream(filename);
|
|
||||||
transfer(s, f, 1024);
|
|
||||||
f.close();
|
|
||||||
// System.out.println(" ... "+new File(filename).length()+" bytes");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void transfer(InputStream in, OutputStream out, int buffer) throws IOException {
|
|
||||||
byte[] read = new byte[buffer]; // Your buffer size.
|
|
||||||
while (0 < (buffer = in.read(read)))
|
|
||||||
out.write(read, 0, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of the buffer to read/write data
|
|
||||||
*/
|
|
||||||
private static final int BUFFER_SIZE = 4096;
|
|
||||||
/**
|
|
||||||
* Extracts a zip file specified by the zipFilePath to a directory specified by
|
|
||||||
* destDirectory (will be created if does not exists)
|
|
||||||
* @param zipFilePath
|
|
||||||
* @param destDirectory
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public void unzip(String zipFilePath, String destDirectory) throws IOException {
|
|
||||||
File destDir = new File(destDirectory);
|
|
||||||
if (!destDir.exists()) {
|
|
||||||
destDir.mkdir();
|
|
||||||
}
|
|
||||||
ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
|
|
||||||
ZipEntry entry = zipIn.getNextEntry();
|
|
||||||
// iterates over entries in the zip file
|
|
||||||
while (entry != null) {
|
|
||||||
String filePath = destDirectory + File.separator + entry.getName();
|
|
||||||
if (!entry.isDirectory()) {
|
|
||||||
// if the entry is a file, extracts it
|
|
||||||
extractFile(zipIn, filePath);
|
|
||||||
} else {
|
|
||||||
// if the entry is a directory, make the directory
|
|
||||||
File dir = new File(filePath);
|
|
||||||
dir.mkdir();
|
|
||||||
}
|
|
||||||
zipIn.closeEntry();
|
|
||||||
entry = zipIn.getNextEntry();
|
|
||||||
}
|
|
||||||
zipIn.close();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Extracts a zip entry (file entry)
|
|
||||||
* @param zipIn
|
|
||||||
* @param filePath
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
|
|
||||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
|
|
||||||
byte[] bytesIn = new byte[BUFFER_SIZE];
|
|
||||||
int read = 0;
|
|
||||||
while ((read = zipIn.read(bytesIn)) != -1) {
|
|
||||||
bos.write(bytesIn, 0, read);
|
|
||||||
}
|
|
||||||
bos.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ProfileComparer(IWorkerContext context, String folder) throws IOException {
|
public ProfileComparer(IWorkerContext context, String folder) throws IOException {
|
||||||
super();
|
super();
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.folder = folder;
|
this.folder = folder;
|
||||||
if (!new File(Utilities.path(folder, "conparison-zip-marker.bin")).exists()) {
|
for (Entry<String, byte[]> e : context.getBinaries().entrySet()) {
|
||||||
String f = Utilities.path(folder, "comparison.zip");
|
TextFile.bytesToFile(e.getValue(), Utilities.path(folder, e.getKey()));
|
||||||
download("https://www.fhir.org/archive/comparison.zip", f);
|
|
||||||
unzip(f, folder);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -502,4 +502,6 @@ public class I18nConstants {
|
||||||
//public static final String
|
//public static final String
|
||||||
//public static final String
|
//public static final String
|
||||||
//public static final String
|
//public static final String
|
||||||
|
public static final String XHTML_URL_EMPTY = "XHTML_URL_EMPTY";
|
||||||
|
public static final String XHTML_URL_INVALID_CHARS = "XHTML_URL_INVALID_CHARS";
|
||||||
}
|
}
|
|
@ -20,10 +20,10 @@ Bundle_MSG_Event_Count = Expected {0} but found {1} event elements
|
||||||
Bundle_Document_Date_Missing = A document must have a date {0}
|
Bundle_Document_Date_Missing = A document must have a date {0}
|
||||||
Bundle_Document_Date_Missing_html = [(type = 'document') implies (meta.lastUpdated.hasValue())]
|
Bundle_Document_Date_Missing_html = [(type = 'document') implies (meta.lastUpdated.hasValue())]
|
||||||
CapabalityStatement_CS_SP_WrongType = Type mismatch - SearchParameter "{0}" type is {1}, but type here is {2}
|
CapabalityStatement_CS_SP_WrongType = Type mismatch - SearchParameter "{0}" type is {1}, but type here is {2}
|
||||||
CodeSystem_CS_VS_IncludeDetails = CodeSystem {0} has a ''all system'' value set of {1}, but the include has extra details
|
CodeSystem_CS_VS_IncludeDetails = CodeSystem {0} has an ''all system'' value set of {1}, but the include has extra details
|
||||||
CodeSystem_CS_VS_Invalid = CodeSystem {0} has a ''all system'' value set of {1}, but doesn''t have a single include
|
CodeSystem_CS_VS_Invalid = CodeSystem {0} has an ''all system'' value set of {1}, but doesn''t have a single include
|
||||||
CodeSystem_CS_VS_MisMatch = CodeSystem {0} has a ''all system'' value set of {1}, but it is an expansion
|
CodeSystem_CS_VS_MisMatch = CodeSystem {0} has an ''all system'' value set of {1}, but it is an expansion
|
||||||
CodeSystem_CS_VS_WrongSystem = CodeSystem {0} has a ''all system'' value set of {1}, but doesn''t have a matching system ({2})
|
CodeSystem_CS_VS_WrongSystem = CodeSystem {0} has an ''all system'' value set of {1}, but doesn''t have a matching system ({2})
|
||||||
Extension_EXT_Context_Wrong = The extension {0} is not allowed to be used at this point (allowed = {1}; this element is [{2})
|
Extension_EXT_Context_Wrong = The extension {0} is not allowed to be used at this point (allowed = {1}; this element is [{2})
|
||||||
Extension_EXT_Count_Mismatch = Extensions count mismatch: expected {0} but found {1}
|
Extension_EXT_Count_Mismatch = Extensions count mismatch: expected {0} but found {1}
|
||||||
Extension_EXT_Count_NotFound = Extension count mismatch: unable to find extension: {0}
|
Extension_EXT_Count_NotFound = Extension count mismatch: unable to find extension: {0}
|
||||||
|
@ -436,7 +436,7 @@ documentmsg = (document)
|
||||||
xml_attr_value_invalid = The XML Attribute {0} has an illegal character
|
xml_attr_value_invalid = The XML Attribute {0} has an illegal character
|
||||||
xml_encoding_invalid = The XML encoding is invalid (must be UTF-8)
|
xml_encoding_invalid = The XML encoding is invalid (must be UTF-8)
|
||||||
xml_stated_encoding_invalid = The XML encoding stated in the header is invalid (must be "UTF-8" if stated)
|
xml_stated_encoding_invalid = The XML encoding stated in the header is invalid (must be "UTF-8" if stated)
|
||||||
XHTML_URL_INVALID = The URL {0} is not valid
|
XHTML_URL_INVALID = The URL {0} is not valid ({1})
|
||||||
MEASURE_MR_GRP_NO_CODE = Group should have a code that matches the group definition in the measure
|
MEASURE_MR_GRP_NO_CODE = Group should have a code that matches the group definition in the measure
|
||||||
MEASURE_MR_GRP_UNK_CODE = The code for this group has no match in the measure definition
|
MEASURE_MR_GRP_UNK_CODE = The code for this group has no match in the measure definition
|
||||||
MEASURE_MR_GRP_DUPL_CODE = The code for this group is duplicated with another group
|
MEASURE_MR_GRP_DUPL_CODE = The code for this group is duplicated with another group
|
||||||
|
@ -480,4 +480,5 @@ MEASURE_M_CRITERIA_CQL_ERROR = Error in {0}: ''{1}''
|
||||||
MEASURE_M_CRITERIA_CQL_NO_ELM = Error in {0}: No compiled version of CQL found
|
MEASURE_M_CRITERIA_CQL_NO_ELM = Error in {0}: No compiled version of CQL found
|
||||||
MEASURE_M_CRITERIA_CQL_ELM_NOT_VALID = = Error in {0}: Compiled version of CQL is not valid
|
MEASURE_M_CRITERIA_CQL_ELM_NOT_VALID = = Error in {0}: Compiled version of CQL is not valid
|
||||||
MEASURE_M_CRITERIA_CQL_NOT_FOUND = The function {1} does not exist in the library {0}
|
MEASURE_M_CRITERIA_CQL_NOT_FOUND = The function {1} does not exist in the library {0}
|
||||||
|
XHTML_URL_EMPTY = URL is empty
|
||||||
|
XHTML_URL_INVALID_CHARS = URL contains Invalid Characters ({0})
|
|
@ -2012,28 +2012,35 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
for (XhtmlNode node : list) {
|
for (XhtmlNode node : list) {
|
||||||
if (node.getNodeType() == NodeType.Element) {
|
if (node.getNodeType() == NodeType.Element) {
|
||||||
if ("a".equals(node.getName())) {
|
if ("a".equals(node.getName())) {
|
||||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, isValidUrl(node.getAttribute("href")), I18nConstants.XHTML_URL_INVALID, node.getAttribute("href"));
|
String msg = checkValidUrl(node.getAttribute("href"));
|
||||||
|
rule(errors, IssueType.INVALID, e.line(), e.col(), path, msg == null, I18nConstants.XHTML_URL_INVALID, node.getAttribute("href"), msg);
|
||||||
} else if ("img".equals(node.getName())) {
|
} else if ("img".equals(node.getName())) {
|
||||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, isValidUrl(node.getAttribute("src")), I18nConstants.XHTML_URL_INVALID, node.getAttribute("src"));
|
String msg = checkValidUrl(node.getAttribute("src"));
|
||||||
|
rule(errors, IssueType.INVALID, e.line(), e.col(), path, msg == null, I18nConstants.XHTML_URL_INVALID, node.getAttribute("src"), msg);
|
||||||
}
|
}
|
||||||
checkUrls(errors, e, path, node.getChildNodes());
|
checkUrls(errors, e, path, node.getChildNodes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidUrl(String value) {
|
private String checkValidUrl(String value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return true;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
if (Utilities.noString(value)) {
|
||||||
|
return context.formatMessage(I18nConstants.XHTML_URL_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Character> invalidChars = new HashSet<>();
|
||||||
for (char ch : value.toCharArray()) {
|
for (char ch : value.toCharArray()) {
|
||||||
if (!(Character.isDigit(ch) || Character.isAlphabetic(ch) || Utilities.existsInList(ch, ';', '?', ':', '@', '&', '=', '+', '$', '.', ',', '/', '%', '-', '_', '~', '#', '[', ']', '!', '\'', '(', ')', '*' ))) {
|
if (!(Character.isDigit(ch) || Character.isAlphabetic(ch) || Utilities.existsInList(ch, ';', '?', ':', '@', '&', '=', '+', '$', '.', ',', '/', '%', '-', '_', '~', '#', '[', ']', '!', '\'', '(', ')', '*' ))) {
|
||||||
return false;
|
invalidChars.add(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
if (invalidChars.isEmpty()) {
|
||||||
} catch (Exception e) {
|
return null;
|
||||||
return false;
|
} else {
|
||||||
|
return context.formatMessage(I18nConstants.XHTML_URL_INVALID_CHARS, invalidChars.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ public class MeasureValidator extends BaseValidator {
|
||||||
String name = cqlRef.substring(0, cqlRef.indexOf("."));
|
String name = cqlRef.substring(0, cqlRef.indexOf("."));
|
||||||
cqlRef = cqlRef.substring(cqlRef.indexOf(".")+1);
|
cqlRef = cqlRef.substring(cqlRef.indexOf(".")+1);
|
||||||
for (Library l : mctxt.libraries()) {
|
for (Library l : mctxt.libraries()) {
|
||||||
if (l.getName().equals(name)) {
|
if (name.equals(l.getName())) {
|
||||||
if (rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), lib == null, I18nConstants.MEASURE_M_CRITERIA_CQL_LIB_DUPL)) {
|
if (rule(errors, IssueType.INVALID, crit.line(), crit.col(), nsc.getLiteralPath(), lib == null, I18nConstants.MEASURE_M_CRITERIA_CQL_LIB_DUPL)) {
|
||||||
lib = l;
|
lib = l;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue