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