001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.test.web; 017 018import javax.servlet.ReadListener; 019import javax.servlet.ServletInputStream; 020import java.io.IOException; 021import java.nio.charset.StandardCharsets; 022 023/** 024 * 参考:https://stackoverflow.com/questions/30484388/inputstream-to-servletinputstream 025 */ 026public class MockServletInputStream extends ServletInputStream { 027 028 final byte[] myBytes; 029 030 private int lastIndexRetrieved = -1; 031 private ReadListener readListener = null; 032 private int readLimit = -1; 033 private int markedPosition = -1; 034 035 public MockServletInputStream(byte[] myBytes) { 036 this.myBytes = myBytes; 037 } 038 039 public MockServletInputStream(String content) { 040 myBytes = content.getBytes(StandardCharsets.UTF_8); 041 } 042 043 @Override 044 public boolean isFinished() { 045 return (lastIndexRetrieved == myBytes.length - 1); 046 } 047 048 @Override 049 public boolean isReady() { 050 return isFinished(); 051 } 052 053 @Override 054 public int available() throws IOException { 055 return (myBytes.length - lastIndexRetrieved - 1); 056 } 057 058 @Override 059 public void close() throws IOException { 060 lastIndexRetrieved = myBytes.length - 1; 061 } 062 063 @Override 064 public void setReadListener(ReadListener readListener) { 065 this.readListener = readListener; 066 if (!isFinished()) { 067 try { 068 readListener.onDataAvailable(); 069 } catch (IOException e) { 070 readListener.onError(e); 071 } 072 } else { 073 try { 074 readListener.onAllDataRead(); 075 } catch (IOException e) { 076 readListener.onError(e); 077 } 078 } 079 } 080 081 082 @Override 083 public boolean markSupported() { 084 return true; 085 } 086 087 @Override 088 public synchronized void mark(int readLimit) { 089 this.readLimit = readLimit; 090 this.markedPosition = lastIndexRetrieved; 091 } 092 093 @Override 094 public synchronized void reset() throws IOException { 095 if (markedPosition == -1) { 096 throw new IOException("No mark found"); 097 } else { 098 lastIndexRetrieved = markedPosition; 099 readLimit = -1; 100 } 101 } 102 103 // Replacement of earlier read method to cope with readLimit 104 @Override 105 public int read() throws IOException { 106 int i; 107 if (!isFinished()) { 108 i = myBytes[lastIndexRetrieved + 1]; 109 lastIndexRetrieved++; 110 if (isFinished() && (readListener != null)) { 111 try { 112 readListener.onAllDataRead(); 113 } catch (IOException ex) { 114 readListener.onError(ex); 115 throw ex; 116 } 117 readLimit = -1; 118 } 119 if (readLimit != -1) { 120 if ((lastIndexRetrieved - markedPosition) > readLimit) { 121 // This part is actually not necessary in our implementation 122 // as we are not storing any data. However we need to respect 123 // the contract. 124 markedPosition = -1; 125 readLimit = -1; 126 } 127 } 128 return i; 129 } else { 130 return -1; 131 } 132 } 133}