/** * Transform an URI accessible from the server into a URI accessible from the client. The mapping * expires with the session. * * @param propertyContext context to obtain session * @param uri server URI to transform * @param filename file name * @param contentType type of the content referred to by the URI, or null if unknown * @param lastModified last modification timestamp * @return client URI */ public static String proxyURI( PropertyContext propertyContext, String uri, String filename, String contentType, long lastModified) { // Create a digest, so that for a given URI we always get the same key final String digest = SecureUtils.digestString(uri, "MD5", "hex"); // Get session final ExternalContext externalContext = (ExternalContext) propertyContext.getAttribute(PipelineContext.EXTERNAL_CONTEXT); final ExternalContext.Session session = externalContext.getSession( true); // NOTE: We force session creation here. Should we? What's the alternative? if (session != null) { // Store mapping into session session .getAttributesMap(ExternalContext.Session.APPLICATION_SCOPE) .put( DYNAMIC_RESOURCES_SESSION_KEY + digest, new DynamicResource(uri, filename, contentType, -1, lastModified)); } // Rewrite new URI to absolute path without the context return DYNAMIC_RESOURCES_PATH + digest; }
/** * Create an XFormsContainingDocument from an XFormsStaticState object. * * <p>Used by XFormsToXHTML. * * @param staticState static state object * @param uriResolver URIResolver for loading instances during initialization (and possibly more, * such as schemas and "GET" submissions upon initialization) * @param response optional response for handling replace="all" during initialization */ public XFormsContainingDocument( XFormsStaticState staticState, XFormsURIResolver uriResolver, ExternalContext.Response response) { super(); // Create UUID for this document instance this.uuid = SecureUtils.randomHexId(); // Initialize request information { initializeRequestInformation(); initializePathMatchers(); } indentedLogger() .startHandleOperation( "initialization", "creating new ContainingDocument (static state object provided).", "uuid", this.uuid); { // Remember static state this.staticState = staticState; this.staticOps = new StaticStateGlobalOps(staticState.topLevelPart()); // NOTE: template is not stored right away, as it depends on the evaluation of the noscript // property. this.xpathDependencies = Version.instance().createUIDependencies(this); // Whether we support updates // NOTE: Reading the property requires the static state set above this.supportUpdates = !isNoUpdates(); // Remember parameters used during initialization this.uriResolver = uriResolver; this.response = response; this.initializing = true; // Initialize the containing document try { initialize(); } catch (Exception e) { throw OrbeonLocationException.wrapException( e, new ExtendedLocationData(null, "initializing XForms containing document")); } } indentedLogger().endHandleOperation(); }
public Item evaluateItem(XPathContext xpathContext) throws XPathException { final Expression dataExpression = argument[0]; final Expression algorithmExpression = argument[1]; final Expression encodingExpression = argument.length == 3 ? argument[2] : null; final String data = dataExpression.evaluateAsString(xpathContext).toString(); final String algorithm = algorithmExpression.evaluateAsString(xpathContext).toString(); final String encoding = encodingExpression != null ? encodingExpression.evaluateAsString(xpathContext).toString() : "base64"; // Create digest final String result = SecureUtils.digestString(data, algorithm, encoding); return new StringValue(result); }
public SubmissionResult connect( final PropertyContext propertyContext, final XFormsModelSubmission.SubmissionParameters p, final XFormsModelSubmission.SecondPassParameters p2, final XFormsModelSubmission.SerializationParameters sp) throws Exception { // Get the instance from shared instance cache // This can only happen is method="get" and replace="instance" and xxforms:cache="true" or // xxforms:shared="application" // Convert URL to string final String absoluteResolvedURLString; { final ExternalContext externalContext = getExternalContext(propertyContext); final URL absoluteResolvedURL = getResolvedSubmissionURL( propertyContext, externalContext, p2.actionOrResource, sp.queryString); absoluteResolvedURLString = absoluteResolvedURL.toExternalForm(); } // Compute a hash of the body if needed final String requestBodyHash; if (sp.messageBody != null) { requestBodyHash = SecureUtils.digestBytes(sp.messageBody, "MD5", "hex"); } else { requestBodyHash = null; } // Parameters to callable final String submissionEffectiveId = submission.getEffectiveId(); final String instanceStaticId; final String modelEffectiveId; final String validation; { // Find and check replacement location final XFormsInstance updatedInstance = checkInstanceToUpdate(propertyContext, p); instanceStaticId = updatedInstance.getId(); modelEffectiveId = updatedInstance.getEffectiveModelId(); validation = updatedInstance.getValidation(); } final boolean isReadonly = p2.isReadonly; final boolean handleXInclude = p2.isHandleXInclude; final long timeToLive = p2.timeToLive; // Create new logger as the submission might be asynchronous final IndentedLogger submissionLogger = new IndentedLogger(containingDocument.getIndentedLogger()); // Obtain replacer // Pass a pseudo connection result which contains information used by getReplacer() // We know that we will get an InstanceReplacer final ConnectionResult connectionResult = createPseudoConnectionResult(absoluteResolvedURLString); final InstanceReplacer replacer = (InstanceReplacer) submission.getReplacer(propertyContext, connectionResult, p); // Try from cache first final XFormsInstance cacheResult = XFormsServerSharedInstancesCache.instance() .findConvertNoLoad( propertyContext, submissionLogger, instanceStaticId, modelEffectiveId, absoluteResolvedURLString, requestBodyHash, isReadonly, handleXInclude, XFormsProperties.isExposeXPathTypes(containingDocument)); if (cacheResult != null) { // Result was immediately available, so return it right away // The purpose of this is to avoid starting a new thread in asynchronous mode if the instance // is already in cache // Here we cheat a bit: instead of calling generically deserialize(), we directly set the // instance document replacer.setInstance(cacheResult); // Return result return new SubmissionResult(submissionEffectiveId, replacer, connectionResult); } else { // Create callable for synchronous or asynchronous loading final Callable<SubmissionResult> callable = new Callable<SubmissionResult>() { public SubmissionResult call() { try { final XFormsInstance newInstance = XFormsServerSharedInstancesCache.instance() .findConvert( propertyContext, submissionLogger, instanceStaticId, modelEffectiveId, absoluteResolvedURLString, requestBodyHash, isReadonly, handleXInclude, XFormsProperties.isExposeXPathTypes(containingDocument), timeToLive, validation, new XFormsServerSharedInstancesCache.Loader() { public ReadonlyXFormsInstance load( PropertyContext propertyContext, String instanceStaticId, String modelEffectiveId, String instanceSourceURI, boolean handleXInclude, long timeToLive, String validation) { // Call regular submission SubmissionResult submissionResult = null; try { // Run regular submission but force synchronous execution and // readonly result final XFormsModelSubmission.SecondPassParameters updatedP2 = p2.amend(false, true); submissionResult = new RegularSubmission(submission) .connect(propertyContext, p, updatedP2, sp); // Check if the connection returned a throwable final Throwable throwable = submissionResult.getThrowable(); if (throwable != null) { // Propagate throw new ThrowableWrapper( throwable, submissionResult.getConnectionResult()); } else { // There was no throwable // We know that RegularSubmission returns a Replacer with an // instance document final DocumentInfo documentInfo = (DocumentInfo) ((InstanceReplacer) submissionResult.getReplacer()) .getResultingDocument(); // Create new shared instance return new ReadonlyXFormsInstance( modelEffectiveId, instanceStaticId, documentInfo, instanceSourceURI, updatedP2.username, updatedP2.password, true, timeToLive, validation, handleXInclude, XFormsProperties.isExposeXPathTypes(containingDocument)); } } catch (ThrowableWrapper throwableWrapper) { // In case we just threw it above, just propagate throw throwableWrapper; } catch (Throwable throwable) { // Exceptions are handled further down throw new ThrowableWrapper( throwable, (submissionResult != null) ? submissionResult.getConnectionResult() : null); } } }); // Here we cheat a bit: instead of calling generically deserialize(), we directly // set the DocumentInfo replacer.setInstance(newInstance); // Return result return new SubmissionResult(submissionEffectiveId, replacer, connectionResult); } catch (ThrowableWrapper throwableWrapper) { // The ThrowableWrapper was thrown within the inner load() method above return new SubmissionResult( submissionEffectiveId, throwableWrapper.getThrowable(), throwableWrapper.getConnectionResult()); } catch (Throwable throwable) { // Any other throwable return new SubmissionResult(submissionEffectiveId, throwable, null); } } }; // Submit the callable // This returns null if the execution is asynchronous return submitCallable(p, p2, callable); } }
/** * This digester is based on some existing public document (not sure which). There are some * changes though. It is not clear anymore why we used that document as a base, as this is purely * internal. * * <p>The bottom line is that the digest should change whenever the infoset of the source XML * document changes. */ public static class DigestContentHandler implements XMLReceiver { private static final int ELEMENT_CODE = Node.ELEMENT_NODE; private static final int ATTRIBUTE_CODE = Node.ATTRIBUTE_NODE; private static final int TEXT_CODE = Node.TEXT_NODE; private static final int PROCESSING_INSTRUCTION_CODE = Node.PROCESSING_INSTRUCTION_NODE; private static final int NAMESPACE_CODE = 0XAA01; // some code that is none of the above private static final int COMMENT_CODE = 0XAA02; // some code that is none of the above /** * 4/6/2005 d : Previously we were using String.getBytes( "UnicodeBigUnmarked" ). ( Believe the * code was copied from RFC 2803 ). This first tries to get a java.nio.Charset with the name if * this fails it uses a sun.io.CharToByteConverter. Now in the case of "UnicodeBigUnmarked" * there is no such Charset so a CharToByteConverter, utf-16be, is used. Unfortunately this * negative lookup is expensive. ( Costing us a full second in the 50thread/512MB test. ) The * solution, of course, is just to use get the appropriate Charset and hold on to it. */ private static final Charset utf16BECharset = Charset.forName("UTF-16BE"); /** Encoder has state and therefore cannot be shared across threads. */ private final CharsetEncoder charEncoder = utf16BECharset.newEncoder(); private java.nio.CharBuffer charBuff = java.nio.CharBuffer.allocate(64); private java.nio.ByteBuffer byteBuff = java.nio.ByteBuffer.allocate(128); private final MessageDigest digest = SecureUtils.defaultMessageDigest(); private void ensureCharBuffRemaining(final int size) { if (charBuff.remaining() < size) { final int cpcty = (charBuff.capacity() + size) * 2; final java.nio.CharBuffer newChBuf = java.nio.CharBuffer.allocate(cpcty); newChBuf.put(charBuff); charBuff = newChBuf; } } private void updateWithCharBuf() { final int reqSize = (int) charEncoder.maxBytesPerChar() * charBuff.position(); if (byteBuff.capacity() < reqSize) { byteBuff = java.nio.ByteBuffer.allocate(2 * reqSize); } // Make ready for read charBuff.flip(); final CoderResult cr = charEncoder.encode(charBuff, byteBuff, true); try { if (cr.isError()) cr.throwException(); // Make ready for read byteBuff.flip(); final byte[] byts = byteBuff.array(); final int len = byteBuff.remaining(); final int strt = byteBuff.arrayOffset(); digest.update(byts, strt, len); } catch (final CharacterCodingException e) { throw new OXFException(e); } catch (java.nio.BufferOverflowException e) { throw new OXFException(e); } catch (java.nio.BufferUnderflowException e) { throw new OXFException(e); } finally { // Make ready for write charBuff.clear(); byteBuff.clear(); } } private void updateWith(final String s) { addToCharBuff(s); updateWithCharBuf(); } private void updateWith(final char[] chArr, final int ofst, final int len) { ensureCharBuffRemaining(len); charBuff.put(chArr, ofst, len); updateWithCharBuf(); } private void addToCharBuff(final char c) { ensureCharBuffRemaining(1); charBuff.put(c); } private void addToCharBuff(final String s) { final int size = s.length(); ensureCharBuffRemaining(size); charBuff.put(s); } public byte[] getResult() { return digest.digest(); } public void setDocumentLocator(Locator locator) {} public void startDocument() throws SAXException { charBuff.clear(); byteBuff.clear(); charEncoder.reset(); } public void endDocument() throws SAXException {} public void startPrefixMapping(String prefix, String uri) throws SAXException { digest.update((byte) ((NAMESPACE_CODE >> 24) & 0xff)); digest.update((byte) ((NAMESPACE_CODE >> 16) & 0xff)); digest.update((byte) ((NAMESPACE_CODE >> 8) & 0xff)); digest.update((byte) (NAMESPACE_CODE & 0xff)); updateWith(prefix); digest.update((byte) 0); digest.update((byte) 0); updateWith(uri); digest.update((byte) 0); digest.update((byte) 0); } public void endPrefixMapping(String prefix) throws SAXException {} public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { digest.update((byte) ((ELEMENT_CODE >> 24) & 0xff)); digest.update((byte) ((ELEMENT_CODE >> 16) & 0xff)); digest.update((byte) ((ELEMENT_CODE >> 8) & 0xff)); digest.update((byte) (ELEMENT_CODE & 0xff)); addToCharBuff('{'); addToCharBuff(namespaceURI); addToCharBuff('}'); addToCharBuff(localName); updateWithCharBuf(); digest.update((byte) 0); digest.update((byte) 0); int attCount = atts.getLength(); digest.update((byte) ((attCount >> 24) & 0xff)); digest.update((byte) ((attCount >> 16) & 0xff)); digest.update((byte) ((attCount >> 8) & 0xff)); digest.update((byte) (attCount & 0xff)); for (int i = 0; i < attCount; i++) { digest.update((byte) ((ATTRIBUTE_CODE >> 24) & 0xff)); digest.update((byte) ((ATTRIBUTE_CODE >> 16) & 0xff)); digest.update((byte) ((ATTRIBUTE_CODE >> 8) & 0xff)); digest.update((byte) (ATTRIBUTE_CODE & 0xff)); final String attURI = atts.getURI(i); final String attNam = atts.getLocalName(i); addToCharBuff('{'); addToCharBuff(attURI); addToCharBuff('}'); addToCharBuff(attNam); updateWithCharBuf(); digest.update((byte) 0); digest.update((byte) 0); final String val = atts.getValue(i); updateWith(val); } } public void endElement(String namespaceURI, String localName, String qName) throws SAXException {} public void characters(char ch[], int start, int length) throws SAXException { digest.update((byte) ((TEXT_CODE >> 24) & 0xff)); digest.update((byte) ((TEXT_CODE >> 16) & 0xff)); digest.update((byte) ((TEXT_CODE >> 8) & 0xff)); digest.update((byte) (TEXT_CODE & 0xff)); updateWith(ch, start, length); digest.update((byte) 0); digest.update((byte) 0); } public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {} public void processingInstruction(String target, String data) throws SAXException { digest.update((byte) ((PROCESSING_INSTRUCTION_CODE >> 24) & 0xff)); digest.update((byte) ((PROCESSING_INSTRUCTION_CODE >> 16) & 0xff)); digest.update((byte) ((PROCESSING_INSTRUCTION_CODE >> 8) & 0xff)); digest.update((byte) (PROCESSING_INSTRUCTION_CODE & 0xff)); updateWith(target); digest.update((byte) 0); digest.update((byte) 0); updateWith(data); digest.update((byte) 0); digest.update((byte) 0); } public void skippedEntity(String name) throws SAXException {} public void startDTD(String name, String publicId, String systemId) throws SAXException {} public void endDTD() throws SAXException {} public void startEntity(String name) throws SAXException {} public void endEntity(String name) throws SAXException {} public void startCDATA() throws SAXException {} public void endCDATA() throws SAXException {} public void comment(char[] ch, int start, int length) throws SAXException { // We do consider comments significant for the purpose of digesting. But should this be an // option? digest.update((byte) ((COMMENT_CODE >> 24) & 0xff)); digest.update((byte) ((COMMENT_CODE >> 16) & 0xff)); digest.update((byte) ((COMMENT_CODE >> 8) & 0xff)); digest.update((byte) (COMMENT_CODE & 0xff)); updateWith(ch, start, length); digest.update((byte) 0); digest.update((byte) 0); } }