1 /*****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19 package org.apache.james.core;
20
21 import org.apache.avalon.framework.container.ContainerUtil;
22 import org.apache.mailet.RFC2822Headers;
23
24 import javax.mail.MessagingException;
25 import javax.mail.internet.MimeMessage;
26 import javax.mail.util.SharedByteArrayInputStream;
27
28 import java.io.BufferedReader;
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.InputStreamReader;
33 import java.util.Enumeration;
34
35 /***
36 * Test the subject folding issue.
37 */
38 public class MimeMessageWrapperTest extends MimeMessageFromStreamTest {
39
40 private final class TestableMimeMessageWrapper extends MimeMessageWrapper {
41
42 boolean messageLoadable = true;
43 boolean headersLoadable = true;
44
45 private TestableMimeMessageWrapper(MimeMessageSource source) throws MessagingException {
46 super(source);
47 }
48
49 public boolean messageParsed() {
50 return messageParsed;
51 }
52
53 public MailHeaders getInnerHeaders() {
54 return (MailHeaders) headers;
55 }
56
57 public boolean isHeadersLoadable() {
58 return headersLoadable;
59 }
60
61 public void setHeadersLoadable(boolean headersLoadable) {
62 this.headersLoadable = headersLoadable;
63 }
64
65 public boolean isMessageLoadable() {
66 return messageLoadable;
67 }
68
69 public void setMessageLoadable(boolean messageLoadable) {
70 this.messageLoadable = messageLoadable;
71 }
72
73 protected synchronized void loadHeaders() throws MessagingException {
74 if (headersLoadable) {
75 super.loadHeaders();
76 } else {
77 throw new IllegalStateException("headersLoadable disabled");
78 }
79 }
80
81 protected synchronized MailHeaders loadHeaders(InputStream is) throws MessagingException {
82 if (headersLoadable) {
83 return (MailHeaders) super.createInternetHeaders(is);
84 } else {
85 throw new IllegalStateException("headersLoadable disabled");
86 }
87 }
88
89 protected synchronized void loadMessage() throws MessagingException {
90 if (messageLoadable) {
91 super.loadMessage();
92 } else {
93 throw new IllegalStateException("messageLoadable disabled");
94 }
95 }
96
97
98
99 }
100
101 TestableMimeMessageWrapper mw = null;
102 String content = "Subject: foo\r\nContent-Transfer-Encoding2: plain";
103 String sep = "\r\n\r\n";
104 String body = "bar\r\n";
105
106 protected MimeMessage getMessageFromSources(String sources) throws Exception {
107 MimeMessageInputStreamSource mmis = null;
108 try {
109 mmis = new MimeMessageInputStreamSource("test", new SharedByteArrayInputStream(sources.getBytes()));
110 } catch (MessagingException e) {
111 }
112 return new TestableMimeMessageWrapper(mmis);
113 }
114
115 protected void setUp() throws Exception {
116 mw = (TestableMimeMessageWrapper) getMessageFromSources(content+sep+body);
117 }
118
119 protected void tearDown() throws Exception {
120 ContainerUtil.dispose(mw);
121 }
122
123
124 public void testDeferredMessageLoading() throws MessagingException, IOException {
125 assertEquals("foo",mw.getSubject());
126 assertFalse(mw.messageParsed());
127 assertEquals("bar\r\n",mw.getContent());
128 assertTrue(mw.messageParsed());
129 assertFalse(mw.isModified());
130 }
131
132 /*** this is commented out due optimisation reverts (JAMES-559)
133 public void testDeferredMessageLoadingWhileWriting() throws MessagingException, IOException {
134 mw.setMessageLoadable(false);
135 assertEquals("foo",mw.getSubject());
136 assertFalse(mw.isModified());
137 mw.setSubject("newSubject");
138 assertEquals("newSubject",mw.getSubject());
139 assertFalse(mw.messageParsed());
140 assertTrue(mw.isModified());
141 mw.setMessageLoadable(true);
142 }
143 */
144
145 public void testDeferredHeaderLoading() throws MessagingException, IOException {
146 mw.setHeadersLoadable(false);
147 try {
148 assertEquals("foo",mw.getSubject());
149 fail("subject should not be loadable here, headers loading is disabled");
150 } catch (IllegalStateException e) {
151
152 }
153 }
154
155 /***
156 * See JAMES-474
157 * MimeMessageWrapper(MimeMessage) should clone the original message.
158 */
159 public void testMessageCloned() throws MessagingException, IOException, InterruptedException {
160 MimeMessageWrapper mmw = new MimeMessageWrapper(mw);
161 ContainerUtil.dispose(mw);
162 mw = null;
163 System.gc();
164 Thread.sleep(200);
165 mmw.writeTo(System.out);
166 }
167
168
169
170
171 public void testGetSubjectFolding() {
172 try {
173 StringBuffer res = new StringBuffer();
174 BufferedReader r = new BufferedReader(new InputStreamReader(mw.getInputStream()));
175 String line;
176 while (r.ready()) {
177 line = r.readLine();
178 res.append(line+"\r\n");
179 }
180 r.close();
181 assertEquals(body,res.toString());
182 } catch (MessagingException e) {
183
184 e.printStackTrace();
185 } catch (IOException e) {
186
187 e.printStackTrace();
188 }
189 }
190
191
192
193
194 public void testAddHeaderAndSave() {
195 try {
196 mw.addHeader("X-Test", "X-Value");
197
198 assertEquals("X-Value", mw.getHeader("X-Test")[0]);
199
200 mw.saveChanges();
201
202 ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
203 mw.writeTo(rawMessage);
204
205 assertEquals("X-Value", mw.getHeader("X-Test")[0]);
206
207 String res = rawMessage.toString();
208
209 boolean found = res.indexOf("X-Test: X-Value") > 0;
210 assertEquals(true,found);
211
212 } catch (MessagingException e) {
213
214 e.printStackTrace();
215 } catch (IOException e) {
216
217 e.printStackTrace();
218 }
219 }
220
221
222 public void testReplaceReturnPathOnBadMessage() throws Exception {
223 MimeMessage message = getMessageWithBadReturnPath();
224 message.setHeader(RFC2822Headers.RETURN_PATH, "<test@test.de>");
225 Enumeration e = message.getMatchingHeaderLines(new String[] {"Return-Path"});
226 assertEquals("Return-Path: <test@test.de>",e.nextElement());
227 assertFalse(e.hasMoreElements());
228 Enumeration h = message.getAllHeaderLines();
229 assertEquals("Return-Path: <test@test.de>",h.nextElement());
230 assertFalse(h.nextElement().toString().startsWith("Return-Path:"));
231 }
232
233 public void testAddReturnPathOnBadMessage() throws Exception {
234 MimeMessage message = getMessageWithBadReturnPath();
235 message.addHeader(RFC2822Headers.RETURN_PATH, "<test@test.de>");
236
237 Enumeration e = message.getMatchingHeaderLines(new String[] {"Return-Path"});
238 assertEquals("Return-Path: <test@test.de>",e.nextElement());
239 assertEquals("Return-Path: <mybadreturn@example.com>",e.nextElement());
240
241 Enumeration h = message.getAllHeaderLines();
242 assertEquals("Return-Path: <test@test.de>",h.nextElement());
243 }
244
245 }