1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.ajp;
15
16 import java.io.IOException;
17 import java.io.UnsupportedEncodingException;
18 import java.util.HashMap;
19
20 import org.eclipse.jetty.http.AbstractGenerator;
21 import org.eclipse.jetty.http.HttpFields;
22 import org.eclipse.jetty.http.HttpGenerator;
23 import org.eclipse.jetty.http.HttpTokens;
24 import org.eclipse.jetty.http.HttpVersions;
25 import org.eclipse.jetty.io.Buffer;
26 import org.eclipse.jetty.io.Buffers;
27 import org.eclipse.jetty.io.ByteArrayBuffer;
28 import org.eclipse.jetty.io.EndPoint;
29 import org.eclipse.jetty.io.EofException;
30 import org.eclipse.jetty.util.StringUtil;
31 import org.eclipse.jetty.util.log.Log;
32
33
34
35
36
37 public class Ajp13Generator extends AbstractGenerator
38 {
39 private static HashMap __headerHash = new HashMap();
40
41 static
42 {
43 byte[] xA001 =
44 { (byte) 0xA0, (byte) 0x01 };
45 byte[] xA002 =
46 { (byte) 0xA0, (byte) 0x02 };
47 byte[] xA003 =
48 { (byte) 0xA0, (byte) 0x03 };
49 byte[] xA004 =
50 { (byte) 0xA0, (byte) 0x04 };
51 byte[] xA005 =
52 { (byte) 0xA0, (byte) 0x05 };
53 byte[] xA006 =
54 { (byte) 0xA0, (byte) 0x06 };
55 byte[] xA007 =
56 { (byte) 0xA0, (byte) 0x07 };
57 byte[] xA008 =
58 { (byte) 0xA0, (byte) 0x08 };
59 byte[] xA009 =
60 { (byte) 0xA0, (byte) 0x09 };
61 byte[] xA00A =
62 { (byte) 0xA0, (byte) 0x0A };
63 byte[] xA00B =
64 { (byte) 0xA0, (byte) 0x0B };
65 __headerHash.put("Content-Type", xA001);
66 __headerHash.put("Content-Language", xA002);
67 __headerHash.put("Content-Length", xA003);
68 __headerHash.put("Date", xA004);
69 __headerHash.put("Last-Modified", xA005);
70 __headerHash.put("Location", xA006);
71 __headerHash.put("Set-Cookie", xA007);
72 __headerHash.put("Set-Cookie2", xA008);
73 __headerHash.put("Servlet-Engine", xA009);
74 __headerHash.put("Status", xA00A);
75 __headerHash.put("WWW-Authenticate", xA00B);
76
77 }
78
79
80
81
82 private static final byte[] AJP13_CPONG_RESPONSE =
83 { 'A', 'B', 0, 1, 9};
84
85 private static final byte[] AJP13_END_RESPONSE =
86 { 'A', 'B', 0, 2, 5, 1 };
87
88
89
90
91
92 private static final byte[] AJP13_MORE_CONTENT =
93 { 'A', 'B', 0, 3, 6, 31, -7 };
94
95 private static String SERVER = "Server: Jetty(7.x.x)";
96
97 public static void setServerVersion(String version)
98 {
99 SERVER = "Jetty(" + version + ")";
100 }
101
102
103 private boolean _expectMore = false;
104
105 private boolean _needMore = false;
106
107 private boolean _needEOC = false;
108
109 private boolean _bufferPrepared = false;
110
111
112 public Ajp13Generator(Buffers buffers, EndPoint io)
113 {
114 super(buffers, io);
115 }
116
117
118 @Override
119 public boolean isRequest()
120 {
121 return false;
122 }
123
124
125 @Override
126 public boolean isResponse()
127 {
128 return true;
129 }
130
131 @Override
132 public void reset(boolean returnBuffers)
133 {
134 super.reset(returnBuffers);
135
136 _needEOC = false;
137 _needMore = false;
138 _expectMore = false;
139 _bufferPrepared = false;
140 _last=false;
141
142
143
144 _state = STATE_HEADER;
145
146 _status = 0;
147 _version = HttpVersions.HTTP_1_1_ORDINAL;
148 _reason = null;
149 _method = null;
150 _uri = null;
151
152 _contentWritten = 0;
153 _contentLength = HttpTokens.UNKNOWN_CONTENT;
154 _last = false;
155 _head = false;
156 _noContent = false;
157 _persistent = true;
158
159
160
161 _header = null;
162 _buffer = null;
163 _content = null;
164
165 }
166
167
168 @Override
169 public int getContentBufferSize()
170 {
171 try
172 {
173 initContent();
174 }
175 catch(IOException e)
176 {
177 throw new RuntimeException(e);
178 }
179 return super.getContentBufferSize()-7;
180 }
181
182
183 @Override
184 public void increaseContentBufferSize(int contentBufferSize)
185 {
186
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 public void addContent(Buffer content, boolean last) throws IOException
205 {
206 if (_noContent)
207 {
208 content.clear();
209 return;
210 }
211
212 if (content.isImmutable())
213 throw new IllegalArgumentException("immutable");
214
215 if (_last || _state == STATE_END)
216 {
217 Log.debug("Ignoring extra content {}", content);
218 content.clear();
219 return;
220 }
221 _last = last;
222
223 if(!_endp.isOpen())
224 {
225 _state = STATE_END;
226 return;
227 }
228
229
230 if (_content != null && _content.length() > 0)
231 {
232
233 flushBuffer();
234 if (_content != null && _content.length() > 0)
235 throw new IllegalStateException("FULL");
236 }
237
238 _content = content;
239
240 _contentWritten += content.length();
241
242
243 if (_head)
244 {
245
246 content.clear();
247 _content = null;
248 }
249 else
250 {
251
252 initContent();
253
254 int len = 0;
255 len = _buffer.put(_content);
256
257
258 if (len > 0 && _buffer.space() == 0)
259 {
260 len--;
261 _buffer.setPutIndex(_buffer.putIndex() - 1);
262 }
263
264 _content.skip(len);
265
266 if (_content.length() == 0)
267 _content = null;
268 }
269 }
270
271
272
273
274
275
276
277
278
279
280 public boolean addContent(byte b) throws IOException
281 {
282
283 if (_noContent)
284 return false;
285
286 if (_last || _state == STATE_END)
287 throw new IllegalStateException("Closed");
288
289
290 if(!_endp.isOpen())
291 {
292 _state = STATE_END;
293 return false;
294 }
295
296
297 if (_content != null && _content.length() > 0)
298 {
299 flushBuffer();
300 if (_content != null && _content.length() > 0)
301 throw new IllegalStateException("FULL");
302 }
303
304 _contentWritten++;
305
306
307 if (_head)
308 return false;
309
310
311 initContent();
312
313
314
315 _buffer.put(b);
316
317 return _buffer.space() <= 1;
318 }
319
320
321
322
323
324
325
326
327
328 @Override
329 public int prepareUncheckedAddContent() throws IOException
330 {
331 if (_noContent)
332 return -1;
333
334 if (_last || _state == STATE_END)
335 throw new IllegalStateException("Closed");
336
337
338 if(!_endp.isOpen())
339 {
340 _state = STATE_END;
341 return -1;
342 }
343
344
345 Buffer content = _content;
346 if (content != null && content.length() > 0)
347 {
348 flushBuffer();
349 if (content != null && content.length() > 0)
350 throw new IllegalStateException("FULL");
351 }
352
353
354 initContent();
355
356 _contentWritten -= _buffer.length();
357
358
359 if (_head)
360 return Integer.MAX_VALUE;
361
362 return _buffer.space() - 1;
363 }
364
365
366 @Override
367 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
368 {
369 if (_state != STATE_HEADER)
370 return;
371
372 if (_last && !allContentAdded)
373 throw new IllegalStateException("last?");
374 _last = _last | allContentAdded;
375
376 boolean has_server = false;
377 if (_persistent==null)
378 _persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
379
380
381 if (_header == null)
382 _header = _buffers.getHeader();
383
384 Buffer tmpbuf = _buffer;
385 _buffer = _header;
386
387 try
388 {
389
390 _buffer.put((byte) 'A');
391 _buffer.put((byte) 'B');
392 addInt(0);
393 _buffer.put((byte) 0x4);
394 addInt(_status);
395 if (_reason == null)
396 _reason=HttpGenerator.getReasonBuffer(_status);
397 if (_reason == null)
398 _reason = new ByteArrayBuffer(Integer.toString(_status));
399 addBuffer(_reason);
400
401 if (_status == 100 || _status == 204 || _status == 304)
402 {
403 _noContent = true;
404 _content = null;
405 }
406
407
408
409 int field_index = _buffer.putIndex();
410 addInt(0);
411
412 int num_fields = 0;
413
414 if (fields != null)
415 {
416
417 int s=fields.size();
418 for (int f=0;f<s;f++)
419 {
420 HttpFields.Field field = fields.getField(f);
421 if (field==null)
422 continue;
423 num_fields++;
424
425 byte[] codes = (byte[]) __headerHash.get(field.getName());
426 if (codes != null)
427 {
428 _buffer.put(codes);
429 }
430 else
431 {
432 addString(field.getName());
433 }
434 addString(field.getValue());
435 }
436 }
437
438 if (!has_server && _status > 100 && getSendServerVersion())
439 {
440 num_fields++;
441 addString("Server");
442 addString(SERVER);
443 }
444
445
446
447
448 int tmp = _buffer.putIndex();
449 _buffer.setPutIndex(field_index);
450 addInt(num_fields);
451 _buffer.setPutIndex(tmp);
452
453
454
455
456 int payloadSize = _buffer.length() - 4;
457
458
459
460 addInt(2, payloadSize);
461 }
462 finally
463 {
464 _buffer = tmpbuf;
465 }
466
467
468 _state = STATE_CONTENT;
469
470 }
471
472
473
474
475
476
477
478 @Override
479 public void complete() throws IOException
480 {
481 if (_state == STATE_END)
482 return;
483
484 super.complete();
485
486 if (_state < STATE_FLUSHING)
487 {
488 _state = STATE_FLUSHING;
489 _needEOC = true;
490 }
491
492 flushBuffer();
493 }
494
495
496 @Override
497 public long flushBuffer() throws IOException
498 {
499 try
500 {
501 if (_state == STATE_HEADER && !_expectMore)
502 throw new IllegalStateException("State==HEADER");
503 prepareBuffers();
504
505 if (_endp == null)
506 {
507
508
509
510
511
512
513 if (!_expectMore && _needEOC && _buffer != null)
514 {
515 _buffer.put(AJP13_END_RESPONSE);
516 }
517 _needEOC = false;
518 return 0;
519 }
520
521
522
523 int total = 0;
524 long last_len = -1;
525 Flushing: while (true)
526 {
527 int len = -1;
528 int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
529
530
531 switch (to_flush)
532 {
533 case 7:
534 throw new IllegalStateException();
535
536
537 case 6:
538 len = _endp.flush(_header, _buffer, null);
539
540 break;
541 case 5:
542 throw new IllegalStateException();
543
544
545 case 4:
546 len = _endp.flush(_header);
547 break;
548 case 3:
549 throw new IllegalStateException();
550
551
552 case 2:
553 len = _endp.flush(_buffer);
554
555 break;
556 case 1:
557 throw new IllegalStateException();
558
559
560 case 0:
561 {
562
563 if (_header != null)
564 _header.clear();
565
566 _bufferPrepared = false;
567
568 if (_buffer != null)
569 {
570 _buffer.clear();
571
572
573
574 _buffer.setPutIndex(7);
575 _buffer.setGetIndex(7);
576
577
578
579
580
581 if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
582 {
583
584 _buffer.put(_content);
585 _content.clear();
586 _content = null;
587 break Flushing;
588 }
589
590 }
591
592
593
594
595 if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
596 {
597 if (_state == STATE_FLUSHING)
598 _state = STATE_END;
599
600
601
602
603
604
605
606 break Flushing;
607 }
608
609
610 prepareBuffers();
611 }
612 }
613
614
615
616 if (len <= 0)
617 {
618 if (last_len <= 0)
619 break Flushing;
620 break;
621 }
622 last_len = len;
623 total += len;
624 }
625
626 return total;
627 }
628 catch (IOException e)
629 {
630 Log.ignore(e);
631 throw (e instanceof EofException) ? e : new EofException(e);
632 }
633
634 }
635
636
637 private void prepareBuffers()
638 {
639 if (!_bufferPrepared)
640 {
641
642
643 if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
644 {
645
646 int len = _buffer.put(_content);
647
648
649 if (len > 0 && _buffer.space() == 0)
650 {
651 len--;
652 _buffer.setPutIndex(_buffer.putIndex() - 1);
653 }
654 _content.skip(len);
655
656 if (_content.length() == 0)
657 _content = null;
658
659 if (_buffer.length() == 0)
660 {
661 _content = null;
662 }
663 }
664
665
666 if (_buffer != null)
667 {
668
669 int payloadSize = _buffer.length();
670
671
672
673
674
675
676 if (payloadSize > 0)
677 {
678 _bufferPrepared = true;
679
680 _buffer.put((byte) 0);
681 int put = _buffer.putIndex();
682 _buffer.setGetIndex(0);
683 _buffer.setPutIndex(0);
684 _buffer.put((byte) 'A');
685 _buffer.put((byte) 'B');
686 addInt(payloadSize + 4);
687 _buffer.put((byte) 3);
688 addInt(payloadSize);
689 _buffer.setPutIndex(put);
690 }
691 }
692
693 if (_needMore)
694 {
695
696 if (_header == null)
697 {
698 _header = _buffers.getHeader();
699 }
700
701 if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
702 {
703 _header.put(AJP13_MORE_CONTENT);
704 _needMore = false;
705 }
706 else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
707 {
708
709
710 _buffer.put(AJP13_MORE_CONTENT);
711 _needMore = false;
712 _bufferPrepared = true;
713 }
714
715 }
716
717 if (!_expectMore && _needEOC)
718 {
719 if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
720 {
721
722 _header.put(AJP13_END_RESPONSE);
723 _needEOC = false;
724 }
725 else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
726 {
727
728
729
730 _buffer.put(AJP13_END_RESPONSE);
731 _needEOC = false;
732 _bufferPrepared = true;
733 }
734 }
735 }
736 }
737
738
739 @Override
740 public boolean isComplete()
741 {
742 return !_expectMore && _state == STATE_END;
743 }
744
745
746 private void initContent() throws IOException
747 {
748 if (_buffer == null)
749 {
750 _buffer = _buffers.getBuffer();
751 _buffer.setPutIndex(7);
752 _buffer.setGetIndex(7);
753 }
754 }
755
756
757 private void addInt(int i)
758 {
759 _buffer.put((byte) ((i >> 8) & 0xFF));
760 _buffer.put((byte) (i & 0xFF));
761 }
762
763
764 private void addInt(int startIndex, int i)
765 {
766 _buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
767 _buffer.poke((startIndex + 1), (byte) (i & 0xFF));
768 }
769
770
771 private void addString(String str) throws UnsupportedEncodingException
772 {
773 if (str == null)
774 {
775 addInt(0xFFFF);
776 return;
777 }
778
779
780
781 byte[] b = str.getBytes(StringUtil.__ISO_8859_1);
782
783 addInt(b.length);
784
785 _buffer.put(b);
786 _buffer.put((byte) 0);
787 }
788
789
790 private void addBuffer(Buffer b)
791 {
792 if (b == null)
793 {
794 addInt(0xFFFF);
795 return;
796 }
797
798 addInt(b.length());
799 _buffer.put(b);
800 _buffer.put((byte) 0);
801 }
802
803
804 public void getBodyChunk() throws IOException
805 {
806 _needMore = true;
807 _expectMore = true;
808 flushBuffer();
809 }
810
811
812 public void gotBody()
813 {
814 _needMore = false;
815 _expectMore = false;
816 }
817
818
819
820 public void sendCPong() throws IOException
821 {
822
823 Buffer buff = _buffers.getBuffer();
824 buff.put(AJP13_CPONG_RESPONSE);
825
826
827 do
828 {
829 _endp.flush(buff);
830 }
831 while(buff.length() >0);
832 _buffers.returnBuffer(buff);
833
834 reset(true);
835
836 }
837
838
839
840 }