/**
   * 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();
  }
Exemple #3
0
  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);
    }
  }
Exemple #5
0
  /**
   * 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);
    }
  }