ארכיון עבור הקטגוריה אינטרנט
הערה: יש סקר בסוף.
סקירה היסטורית
בראשית היה ASCII (האמת היא שהיו קידודים לפני ASCII אבל הם לא מעניינים אותנו).
אסקי נועד בעיקר לתווים באנגלית, הערך של ‘A’ הוא 65, הערך של רווח הוא 32 וכן הלאה. ASCII הוא קידוד 7 ביטים, מה שאומר שהוא משתמש ב128 אפשרויות מתוך 256 האפשרויות שנכנסות בbyte.
הבעיה עם אסקי היא שהוא לא כולל תווים של שפות אחרות - קירילית ועברית למשל.
Code page
הפתרון המתבקש הוא להשתמש בערכים 128-255 כדי לייצג את האותיות החסרות.
הבעיה היא שהרבה אנשים חשבו על הפתרון הזה בו זמנית, ומטבע הדברים היו הרבה טבלאות כאלו, לפעמים אפילו כמה בתוך אותה מדינה.
לא נחמד, כי מסמך שנכתב תוך שימוש בטבלא אחת לא הוצג כמו שצריך למי שהשתמש בטבלא אחרת.
בשלב מסויים הוגדרו סטנדרטים על ידי ארגון התקינה האמריקאי (ANSI) , שנקראו Code pages, מה שעזר למנוע הווצרות של טבלאות מיותרות חדשות.
הבעיה העיקרית עם הפתרון הזה הוא שאי אפשר לערבב שפות שמשתמשות בקודים שונים.
בנוסף, הוא נותן פתרון רק לשפות בעלות פחות מ128 אותיות.
באסיה הוגדר תקן בשם DBCS - Double byte character set, שנועד לתת פתרון לשפות האסיאתיות.
התקן הזה השתמש בקידוד באורך משתנה: חלק מהתווים היו באורך בייט אחד וחלק באורך שני בייטים, ובאופן כללי היה מבלבל למדי.
UNICODE
יוניקוד הוא שם הקוד לטבלא גדולה מאוד שמתאימה מספר לכל אות ידועה (וגם כמה משפות מומצאות כמו קלינגונית), מכיוון שיש טבלא אחת לכל השפות - אין בעיה לערבב בין שפות שונות.
מיתוס נפוץ הוא שניתן לייצג כל אות ביוניקוד בעזרת מספר בין 16 סיביות (או במילים אחרות, שיש פחות מ65536 אותיות ביוניקוד).
זה לא נכון, ולמעשה יש ביוניקוד גרסא 4.0 קרוב ל240,000 סימנים, מה שאומר שצריך לפחות 3 בתים כדי למספר את כל התווים ביוניקוד.
מחרוזת ביוניקוד היא בסך הכל סדרה של מספרים, כאשר כל מספר הוא המיקום של אות מסויימת בטבלא.
מקובל לסמן תו יוניקוד בסימן כמו U+0041, כאשר U+ אומר שזה יוניקוד והמספר שאחריו הוא קוד האות בבסיס הקסדצימלי.
לא במקרה, 128 התווים הראשונים ביוניקוד הם בדיוק אותם 128 התוים הראשונים באסקי וברוב קידודי הCode page.
המחרוזת hello ביוניקוד תכתב ככה:
U+0048 U+0065 U+006C U+006C U+006F
אם נשמור את זה, נקבל:
00 48 00 65 00 6C 00 6C 00 6F
או
48 00 65 00 6C 00 6C 00 6F 00
תלוי בשיטת בה אנחנו מקודדים ספרות בזכרון המחשב (Little endian או Big endian).
כדי להבחין בין שתי השיטות ישנה תוספת של התווים FE FF בתחילת מחרוזת יוניקוד (שתראה ככה או הפוך, לפי הEndianness של המכונה).
הסימון הזה נקרא Unicode Byte Order Mark, או בקיצור BOM - והוא גורם ללא מעט צרות לדפדפנים שכתובים רע.
UTF-8
באו האמריקאים ושאלו, מה אנחנו צריכים את האפסים האלו באמצע המחרוזת? הרי המחרוזת תופסת פי שתיים, והם גם מבלבלים תוכנות שמתייחסות ל0 בתור סימון לסוף המחרוזת (מקובל בC וC++).
וככה נולד UTF-8.
UTF-8 הוא שיטה לקידוד יוניקוד בקידוד בעל אורך משתנה.

כשקוראים UTF-8, מסתכלים על התו הראשון ולפי הביטים הראשונים אפשר לדעת בדיוק על כמה בתים האות הבאה יושבת.
UTF-8 הפך לסטנדרט המקובל ביותר לקידוד מחרוזות יוניקוד.
PHP ויוניקוד
PHP התמיכה של PHP 4 ו5 ביוניקוד חלקית ביותר.
מחרוזות בPHP הן בעצם סדרה של בייטים ולא יותר ולמרות שתמיד אפשר להשתמש במחרוזת PHP כדי לשמור מחרוזות בקידודים שונים - רק במקרה שהPHP קומפל עם תמיכה בmb_string יהיו לנו פונקציות מיוחדות לטיפול במחרוזות מרובות בתים.
פתרון נוסף הוא להשתמש בספריה iconv, שמוסיפה לPHP יכולות המרה של קידודים, אבל היא לא מגיעה כברירת מחדל עם PHP ומי שרוצה תוכנה שתוכל לרוץ בקלות בכל מחשב ימנע ממנה.
בPHP 6 שמתבשל לאיטו צפויה תמיכה ביוניקוד, UTF-8 וכל זה, אבל זה עדיין לא שוחרר, ואם לשפוט לפי הקצב שלוקח לשוק לאמץ את PHP5 - אז PHP6 לא יהיה רלוונטי בשנים הקרובות למי שרוצה לשחרר תוכנה שתרוץ בכל מחשב.
מכיוון שהפונקציות הסטנדרטיות בPHP תומכות בעצם רק בקידוד שבו כל אות תופסת בייט אחד, הן יכולות ליצור בעיות מעניינות.
אם תקבלו מחרוזת שמקודדת בUTF-8, נניח “שלום”, ותציגו אותה בדפדפן האורך שלה יהיה 4 אותיות. אם תשתמשו בפונקצית הPHP לחישוב אורך של מחרוזות, תקבלו שהאורך שלה הוא 8 תווים, כי כל אות מקודדת בשני בתים.
אם תנסו את אותו דבר על המחרוזת המעורבת “שלום SHALOM”, תקבלו שהאורך הוא 8 + 1 + 6 = 15.
לעומת זאת, אם תשתמשו בmb_strlen תקבלו את האורך הנכון.
בעיה נוספת היא בעיה של חיתוך מחרוזות UTF-8.
אם נשתמש בפונקציה wordwrap לחיתוך מחרוזות UTF8, היא עלולה לחתוך אות בין שני הבתים שלה, ובעצם להעלים אותה. לא נעים.
הפתרון שלי היה לכתוב גרסא של wordwrap שעובדת על מחרוזות UTF-8.
אפשר להבין למה מפתחי PHP מתבלבלים כשהם מתעסקים עם מחרוזות בUTF-8.
המרות וקיבועים
למרות שרוב אתרי האינטרנט בימינו השכילו לעבור לUTF-8 לקידוד של מחרוזות, עדיין יש אתרים מסויימים שמשתמשים בקידודים מבוססי Code page. למשל - מנוע החיפוש של Walla מקודד לפעמים את מילות החיפוש בכתובת בקידוד עברית 1255 (עברית חלונות), ולפעמים בקידוד UTF-8. מאוד נחמד מצידם של המפתחים לפחות להעביר את הקידוד כחלק מהכתובת (e=hew לעברית 1255 וe=utf לutf8).
לא חסרות דוגמאות אחרות, בעיקר במנועי חיפוש מקומיים (yandex.ru, mail.ru שמשתמשים בקידוד קירילי 1251) ועוד.
מכיון שאני רוצה שמילות החיפוש יוצגו כמו שצריך בFireStats, צריך להמיר את הקידודים האלו לUTF-8.
הבעיה היא שכאמור - אין תמיכה מובטחת בiconv שמאפשר המרות כאלו, ולכן נאלצתי לכתוב בעצמי ספריית המרות קטנה מקידודי codepage כלשהם לקידוד UTF8. הספריה מסתמכת על טבלאות המרה שאפשר להשיג באתר הראשי של יוניקוד.
הרעיון של הספריה הוא להמיר באמצעות הטבלא את המחרוזת ליוניקוד, ואז לקודד אותה לUTF8.
וזו האגדה על אסקי יוניקוד וUTF-8.
 Loading ...
 Loading ...
קריאה נוספת
Joel on software במאמר מצויין על יוניקוד
מצגת על השרדות עם UTF-8
שאלות נפוצות על יוניקוד וUTF-8 בלינוקס ויוניקס
21 תגובות »
בהמשך לפוסט האחרון על בעיות רשת מוזרות, הנה עוד אחת.
אפליקציית ג’אווה שכתבנו עובדת טוב לרוב האנשים, אבל משום מה “נתקעת” בהתחברות לחלק מהאנשים.
בבדיקה, נראה שהאפליקציה מתחברת לשרת, מקבלת תשובה ממנו, אבל לא קוראת את התוכן של התשובה.
בבדיקה מעמיקה יותר, רואים שהאפליקציה ניגשת לשדה הContent-Length של התשובה, ומקבלת משם 1-, מה שמרמז על זה שאין בתגובת הHTTP שדה של Content-Length.
בדיקה קטנה עם WireShark (לשעבר Ethereal) מראה את זה:
HTTP/1.1 200 OK
Date: Thu, 31 Jan 2008 13:21:24 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Set-Cookie: ASP.NET_SessionId=j2hx2qvprzec3u55htsykh45; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html
Content-Length: 20877
(המשך התגובה נחתך מחוסר עניין).
אז נראה שהכל בסדר, יש Content-Length בתגובה.
ובכל זאת, אפליקציית הJava מקבלת 1-, ובדיבוג מעמיק אין רמז לContent-Length באובייקט שמייצג את תגובת הHTTP.
אז מה קורה פה?
הצעד הבא הוא לבדוק TCP נקי, בלי טובות של Java בפירסור התגובה.
תוכנית קטנה שמתחברת בTCP לשרת הHTTP, שולחת את הבקשה ומדפיסה את התוצאה מהשרת הפיקה את הפלט הזה:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Thu, 31 Jan 2008 13:21:24 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Set-Cookie: ASP.NET_SessionId=j2hx2qvprzec3u55htsykh45; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html
————–: —–
יש פה כמה דברים שצריך לשים אליהם לב:
1. פתאום יש לנו בתשובה Transfer-Encoding: chunked.
2. מה זה איפה שקודם היה לנו Content-Length? ————–: —– ?? איזה וודו שחור פועל פה?
יש לציין שבזמן שאני מקבל את הנתונים האלו בתוכנית, אני מקבל נתונים זהים למה שראיתי קודם WireShark, כלומר - המחשב מקבל את הנתונים בצורה תקינה, אבל התוכנית מקבלת אותם אחרי טיפול.
כדי לנטרל אפשרות שJava התחלקה על השכל, ניסיתי (בעזרתו של חבר מהעבודה) להריץ תוכנית שעושה את אותו דבר בדיוק, רק שכתובה בC#.
לא במפתיע, התוצאה זהה: אין Content-Length, במקום זה יש שורת מינוסים.
מסקנה, Java לא אשמה הפעם.
אז מה נשאר?
מי משחק בתעבורת הרשת במחשב? אולי זה ווירוס, ואולי זה אנטי וירוס; בכל מקרה מדובר בתוכנה נאלחת.
לא במפתיע, האשם הוא הSymantec Client Firewall, שסורק בזמן אמת את תעבודת הHTTP, מחרבש אותה קלות, ומעביר את הזבל לתוכניות התמימות.
ברגע שנטרלתי את הסריקה שלו את פורט 80, הכל הסתדר.
יש לי משהו לומר למהנדסים של סימנטק:
אתם אינוולידים, מי נתן לכם את הזכות לשבש את התעבורה?
תסרקו, זה בסדר, אבל אין שום הצדקה שבעולם שהתוכניות שקוראות מהרשת יחשפו לשינויים שתרמתם.
אם הייתם עובדים אצלי הייתי משבש לכם את המשכורת.
אם הייתי כותב ווירוסים, הייתי משתמש במידע הזה בכיף כדי לזהות שהמחשב מריץ את הFirewall של סימנטק, שמשאיר עקבות כמו חזיר בחנות בורקסים.
10 תגובות »
012 סמייל קווי זהב (או איך שלא קוראים להם היום), שנולדו מהרכישה של 012 על ידי אינטרנט זהב נחשדים בזיוף של תעבורה אינטרנט שנועדה לגרום להחרמה של משתמשי TorrentLeech.
בעבר היו לי לא מעט בעיות מהירות עם אינטרנט זהב שהסתיימו כשהתנתקתי מהם.
כבר בעבר חשדתי שאינטרנט זהב משתמשת בטכניקות מסויימות כדי לפגוע בקצב ההעלאה של משתמשים, ואם הטענות של מנהלי TorrentLeech נכונות, אז 012 סמייל קווי זהב (או איך שלא קוראים להם היום) עברו את הגבול הדק שבין ניהול משאבים על גבול הלגיטימי לזיוף נתונים כדי להפיק רווחים, פעולה פלילית ללא ספק.
יש דמיון עקרוני רב בין המקרה של Comcast, שזייפו חבילות RST שנועדו לגרום לצד השני לחשוב שהצד המחובר סגר את החיבור לבין מה שסמייל קווי זהב (או איך שלא קוראים להם היום) נחשדים בו.
הייתי אומר שהפתרון של Comcast יותר מתוחכם טכנולוגית ויותר קשה לזיהוי ושהפתרון של 012 (או איך בלה בלה) יותר גס טכנולוגית אבל יותר נבזי בהרבה.
הסיבה היא שהפתרון של 012 (בלה) נועד לגרום לשרתי TorrentLeech לחשוד שהמשתמש מנסה לגרום לאתר לחשוב שהוא העלה כמויות נתונים גדולות ולא סבירות במטרה לגרום להחרמתו מהאתר.
זו מתקפה מאוד ספציפית על משתמשי TorrentLeech, ואם זה אכן קרה, אני מצפה שכל משתמשי TorrentLeech שמחוברים דרך 012 (בלה) יתנתקו ויעברו לספק שלא חוסם/מגביל/מרמה/משקר/עובר על החוק (עדיין?) כמו בזק-בין-לאומי.
הערה:
הטענה של TorrentLeech לא הוכחה עדיין.
הנה ההודעה המקורית של TorrentLeech:
2008-01-24 - ISRAEL USERS
Unfortunately it seems, that a few Israeli ISPs, are intensionally altering the announces to our tracker of their clients, announcing to our tracker false stats (over 8.000.000 TB of upload and download) in order for these users to be probably banned (and save some bandwidth). We made a script to automatically detect this false announce, and reset the user’s account (reset uploaded/downloaded). Although this is NOT a fix, only a temporary solution, we cannot do anything more from our part, since this is not a problem of our tracker. We know that reseting these accounts is not pleasant, but the other alternatives were to ban these accounts or to ban all the Israel Golden Lines ip block (which unfortunately seems very possible in the future, since our tracker gets hammered because of the problem above)
Seems most of the users having this problem use the ISP-> GOLDENLINES
10 תגובות »
UPNP היא טכנולוגיה שנועדה לפשט את התהליך של הוספת שרתים ונקודות קצה לרשת. אחד השימושים הפופולריים של UPNP הוא לאפשר קידום פורטים אוטומטי.
נניח שיש לכם רשת מקומית קטנה מאחורי NAT (תצורה מאוד נפוצה בימינו, כמעט כל מחשב שמחובר לאינטרנט דרך נתב מהווה בעצם רשת מקומית כזו), ותוכנת שיתוף באחד המחשבים רוצה לאפשר התחברות אליה מבחוץ.
לפני UPNP, התוכנה לא תוכל לעשות את זה בעצמה, ומנהל המערכת (או המשתמש התמים שקנה את הנתב) יצטרך להגדיר את הנתב “ולפתוח פורטים”, או ליתר דיוק - לקדם פורטים מסויימים אל המכונה הספציפית.
היום רוב הנתבים תומכים בUPNP, מה שמאפשר לתוכנת השיתוף למצוא את הנתב, לגלות שהוא תומך בקידום פורטים, ולבקש ממנו בדרכי נועם לקדם למחשב עליו היא רצה חבילות מידע שמגיעות לפורטים מסויימים.
מאוד נוח, הכל פשוט עובד.
הבעיה היא שUPNP לא כולל אימות (כי אחרת המשתמש היה צריך להגדיר שם משתמש וסיסמא בנתב לצרכים האלו, ולתת לתוכנת השיתוף את שם המשתמש והסיסמא, דבר לא נוח בעליל!) ולמעשה מאפשר לכל תוכנה שרצה של מחשב בתוך הרשת לבקש קידום פורטים בלי בקרה מיוחדת ובצורה שקופה ונסתרת מהמשתמש.
הבעיה מתחילה כהמשתמש מריץ תוכנה בלי להבין אפילו שזה מה שהוא עושה.
למשל, אתם גולשים לתומכם באינטרנט, בטוחים שהתוכנה היחידה שאתם מפעילים היא הדפדפן, אתם נכנסים לדף כלשהו שמציג אנימציית פלאש.
הופ, הרצתם תוכנה חיצונית.
לא הפלאש, אלא האנימציה עצמה.
בצורה דומה הפעלה של ישומון ג’אווה היא בעצם הפעלה של תוכנה חיצונית בתוך הרשת שלהם. במקרה של ג’אווה המצב עוד יחסית בסדר כי רק ישומונים חתומים יכולים להתחבר לשרתים אחרים מזה שהם ירדו ממנו (ישומים חתומים הם נדירים למדי כי כדי לחתום יש לרכוש חתימה מסמכות שורש כמו Verisign או Thawte, מה שעולה כמה מאות דולרים לשנה ויאפשר זיהוי של מקור הקוד).
לעניין, פלאש מאפשר התחברות לנתב ובקשה לקידום פורטים, בנוסף UPNP מאפשר בנתבים מסויימים לשנות את שרת הDNS של הנתב, מה שיכול לאפשר תכמון של המשתמש ברמות בלתי נתפסות.
מכיוון שכל נתב שנרכש בשנים האחרונות מתהדר בתמיכה בUPNP שמופעלת בדרך כלל כברירת מחדל, הבעיה די חמורה.
מומחי אבטחה מנסים לשכנע אנשים מזה שנים שנתב NAT הוא לא Firewall, אבל רוב האנשים לא מבחינים בהבדל. מבחינתם אם הם מאחורי נתב הם בטוחים והנתב הוא זה שיספוג את ההתקפות.
אז זהו, שלא.
למעשה, ווקטור ההתקפה הזה מנצל את האמון שאנחנו רוכשים למחשבים בתוך הרשת.
למשל, שרותים מקומים רבים מאפשרים התחברות מהמחשב המקומי בלבד (ובודקים שההתחברות מגיעה מהמחשב המקומי). הפעלת פלאש תמימה (ונסתרת) יכולה לעקוף את ההגנה הזו בקלילות (ואם פלאש עדיין לא תומך בקישוריות UDP/TCP, הוא בטח יתמוך בגרסאות הבאות).
מומלץ לנטרל את התמיכה בUPNP בנתב שלכם.
ההתקפה הודגמה בGnuCitizen.
11 תגובות »
נכתב על ידי עמרי בנושא אינטרנט
בשעה טובה, התחילה חקירה נגד Comcast על ההתערבות הנבזית בתעבורת הרשת של המשתמשים שלה.
Comcast נתפסה מזייפת חבילות RST, טכניקה ערמומית ונכלולית להגביל תעבורת אינטרנט (דמיינו שאתם מתקשרים למישהו בטלפון, הוא עונה ואומר שהוא לא יכול לדבר כרגע, רק שבעצם זה לא הוא ענה, אלא ספק הטלפוניה שלהם שהגדיל ראש בכוונה להוריד מהעומס על רשת הטלפונים).
כתבתי כבר שכדאי מאוד שהשוק יראה לComcast שהטריקים האלו לא מקובלים ויכאיב לה איפה שכואב, אחת תתחיל מגפה של ספקיות שחוסמות תעבורת נתונים “לא לגיטימית” לאור יום.
6 תגובות »
נכתב על ידי עמרי בנושא אינטרנט
חיים טוב האמריקאים.
מי שרוצה למצוא סרט פשוט כותב בגוגל את שם העיר וCinema, למשל Renton cinema, ומקבל רשימת בתי קולנוע, ומה כל אחד מהם מציג היום.
מתי אצלנו?
4 תגובות »
לפני כמה שבועות הפיד RSS של TorrentLeech (להלן TL), ספק הסדרות העיקרי שלי, התחיל להחזיר 404 (דף לא נמצא).
אין פה שום דבר חדש, הפיד הזה אף פעם לא היה יציב במיוחד, לכן חיכיתי בסבלנות כשבוע, ואז התלוננתי בערוץ הIRC שהלינק של הפיד לא עובד.
גורם “רשמי” מסר לי שהפיד לא יחזור כי השתמשו בו לרעה.
ניסיתי לברר את פשר השימוש הפוחז, ואפילו הצעתי את עזרתי במציאת פיתרון, אך לשוא:
הילדון זב החוטם מסר שלא משנה מה אני אגיד או אעשה, הפיד לא חוזר.
הסברתי לו בדרכי נועם שאם המידע זמין באתר, אין שום הבדל כי אפשר להפוך אותו לפיד, אבל זה לא עזר.
אז החלטתי לעשות בדיוק את זה, וכך נולדה תוכנה חדשה - TorrentLeech2RSS.
בגדול, הרעיון הוא כזה:
שרת מקומי דוגם את TL, נניח פעם בחצי שעה.
השרת נכנס לTL, מזדהה עם שם המשתמש והסיסמא של המשתמש בTL, מוריד את דף הHTML שמכיל את רשימת הטורנטים בכל אחת מהקטגוריות הנבחרות, מפענח את הדף, ומחלץ ממנו את השם, הלינק, המזהה והתאריך של כל טורנט, ושומר אותם בזכרון.
במקום להשתמש בכתובת הRSS של TL (שאינה עימנו עוד), המשתמש מכניס כתובת של TorrentLeech2RSS, שמכין דף RSS ומחזיר אותו למבקש.
TorrentLeech2RSS גם משכתב את הלינקים בתוך הRSS שיעברו דרכו, כדי שיוכל להוסיף פרטי הזדהות שיעברו לשרת של TL ברגע שהמשתמש מנסה להוריד טורנט (אחרת הTracker של TL לא משתף פעולה עם המשתמש).
בחרתי לכתוב את tl2rss בשפת ג’אווה.
הצעד הראשון, וכנראה הכי קשה בתהליך, הוא להכנס תכנותית לאתר, התהליך מורכב יחסית וכולל כמה שלבים.
כדי להבין מה אני אמור לשלוח ומתי, השתמשתי בWireShark, וניטרתי את התעבורה שנוצרת כשאני מבצע לוגין בעזרת הדפדפן.
שימו לב במיוחד לאפשרת של Follow TCP Stream, שמציגה שיחת HTTP שלמה בצורה ברורה.
ברגע שהקוד הצליח להזדהות מול השרת, לבקש דף שמתאים לקטגוריה רלוונטית זה קל. אבל מה עושים עם הדף?
הדפים של TorrentLeech הם דוגמא לאיך נראה קוד HTML מבולגן ולא תקני, ערבוביה של תגיות HTML שכוללות תוכן, עיצוב ועימוד.
בקיצור, לא משהו שכיף במיוחד לחפוש בתוכו אחרי מידע.
הגישה הנאווית לבעיות כאלו היא שימוש בביטוי רגולרי, אבל זה לא יעבוד טוב בכל המקרים (מה קורה למשל אם יש HTML בתוך התאור של הטורנט?).
בחרתי ללכת לגישה טיפה יותר חזקה, והיא פירוק מלא של הHTML למבנה נתונים בזכרון, וניתוח של אותו מבנה.
ספרית ג’אווה שמאפשרת parsing כזה לHTML היא htmlparser הוותיקה.
אבל גם אם htmlparser מחזירה לנו עץ אובייקטים נוח, איך מוציאים ממנו את מה שמעניין? הוא ענק וסבוך ויותר מכל מסובך.
למזלי מצאתי בונה פילטרים ויזואלי עם htmlparser. אפשר להריץ אותו עם Java web start:
javaws http://htmlparser.sourceforge.net/samples/filterbuilder.jnlp
או פשוט להריץ את הקוד ישירות (org.htmlparser.parserapplications.filterbuilder.FilterBuilder). עורך הפילטרים מאפשר ליצור פילטרים מורכבים בהדרגתיות תוך בדיקה מתמדת של התוצאה על דף הHTML שאתם רוצים לבדוק.
אזהרה: הוא לא הכי ידידותי בעולם, לוקח זמן להתרגל אליו - אבל הוא עובד.
לדוגמא, נניח שאנחנו רוצים לחלץ את רשימת השחקנים מהסרט ביוולף בIMDB.
קודם נכניס בשורה התחתונה את הURL, אחר כך נלחץ על fetch page, ואז נקבל את הHTML כעץ בחלק הימני.

ברגע שיש לנו את הHTML, נתחיל לפלטר. חיפוש קצר אחרי שם של אחד השחקנים (Musician #2) מצא את הטבלא, ולמרבה הנוחות אפשר לראות שclass הCSS שלה הוא cast. זה מצויין, כי זה יאפשר לנו לדוג את הטבלא בקלות:
נוסיף פילטר של תכונות (attributes), נכניס בו את התכונה class עם הערך cast.
קליק ימני על הפילטר, execute filter, ונקבל חלון קטן בצד ימין עם התוצאות.
בינגו, יש לנו את הטבלה.

אבל אנחנו רוצים רק את רשימת השחקנים, אז צריך לעדן את הפילטר.
נוסיף שאנחנו רוצים רק טגים בשם TR, שיש להם הורה שהוא טבלא עם תכונה של class שערכו cast:

אפשר להמשיך, אבל הרעיון - אני מקווה - ברור.
ברגע שאנחנו מרוצים מהפילטר שיצרנו, אפשר לשמור אותו.
זה מה שיוצא (גרסא מקוצרת):
// Generated by FilterBuilder. http://htmlparser.org
// [aced0005737200206f.......17374]
import org.htmlparser.*;
import org.htmlparser.filters.*;
import org.htmlparser.beans.*;
import org.htmlparser.util.*;
public class imdb
{
public static void main (String args[])
{
TagNameFilter filter0 = new TagNameFilter ();
filter0.setName (“TR”);
HasAttributeFilter filter1 = new HasAttributeFilter ();
filter1.setAttributeName (“class”);
filter1.setAttributeValue (“cast”);
HasParentFilter filter2 = new HasParentFilter ();
filter2.setRecursive (false);
filter2.setParentFilter (filter1);
NodeFilter[] array0 = new NodeFilter[2];
array0[0] = filter0;
array0[1] = filter2;
AndFilter filter3 = new AndFilter ();
filter3.setPredicates (array0);
NodeFilter[] array1 = new NodeFilter[1];
array1[0] = filter3;
FilterBean bean = new FilterBean ();
bean.setFilters (array1);
if (0 != args.length)
{
bean.setURL (args[0]);
System.out.println (bean.getNodes ().toHtml ());
}
else
System.out.println (“Usage: java -classpath .:htmlparser.jar:htmllexer.jar imdb <url>”);
}
}
בראש הקובץ יש קידוד של הפילטר, מה שמאפשר לנו לטעון את הקובץ ולהמשיך לעבוד עליו מאותה נקודה.
כדי לקמפל את זה צריך כמובן את htmlfilter.jar בclasspath.
טוב, אז נניח שכתבנו פילטר מתאים, וגיבינו אותו בקצת קוד שמוציא את הנתונים לרשימה נוחה.
איך הופכים את זה לRSS?
בקלות, בעזרת ספרית ג’אווה בשם Rome.
השימוש ברומא פשוט מאוד, הנה דוגמא:
public String getListRSS () throws FeedException
{
SyndFeed feed = new SyndFeedImpl ();
feed. setFeedType(“rss_2.0″);
feed. setTitle(“My RSS!”);
feed. setLink(“http://firefang.net/blog/768″);
feed. setDescription(“A feed for you!”);
List entries = new ArrayList();
feed. setEntries(entries );
Vector v = new Vector();
v. add(“item1″);
v. add(“item2″);
v. add(“item3″);
for (int i = 0; i < v. size(); i++ )
{
SyndEntry entry = new SyndEntryImpl ();
entry. setTitle((String) v. elementAt(i ));
entry. setLink(“http:://imdb.com/”);
entries. add(entry );
}
SyndFeedOutput output = new SyndFeedOutput();
return output.outputString(feed);
}
שמפיקה את הRSS הזה:
<?xml version=“1.0″ encoding=“UTF-8″?>
<rss xmlns:content=“http://purl.org/rss/1.0/modules/content/” xmlns:taxo=“http://purl.org/rss/1.0/modules/taxonomy/” xmlns:rdf=“http://www.w3.org/1999/02/22-rdf-syntax-ns#” xmlns:dc=“http://purl.org/dc/elements/1.1/” version=“2.0″>
<channel>
<title>My RSS!</title>
<link>http://firefang.net/blog/768</link>
<description>A feed for you!</description>
<item>
<title>item1</title>
<link>http:://imdb.com/</link>
<guid>http:://imdb.com/</guid>
</item>
<item>
<title>item2</title>
<link>http:://imdb.com/</link>
<guid>http:://imdb.com/</guid>
</item>
<item>
<title>item3</title>
<link>http:://imdb.com/</link>
<guid>http:://imdb.com/</guid>
</item>
</channel>
</rss>
אז עכשיו שאנחנו יודעים לקחת דף HTML ולהוציא ממנו טקסט של RSS, נשאר רק לאפשר לקורא RSS רגילים לגשת אליו.
הדרך הטבעית תהיה להריץ שרת ווב קטן, שיגיש את קובץ הRSS למי שמבקש.
בחרתי להשתמש בJetty, שהוא שרת ווב קטן וגמיש בג’אווה, שמאפשר גם שילוב פשוט וקל בתוך אפליקציות אחרות.
לא להבהל מגודל ההורדה שלו, כדי להשתמש בו בתוך האפליקציה שלכם מספיק לקחת שלושה Jarים בגודל כולל של כ700K.
ככה משלבים את Jetty בתוך הישום שלכם, שימו לב כמה שזה פשוט.
Handler handler= new AbstractHandler ()
{
public void handle (String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
throws IOException, ServletException
{
response. setContentType(“text/html”);
response. setStatus(HttpServletResponse. SC_OK);
response. getWriter(). println(“<h1>Hello</h1>”);
((Request)request ). setHandled(true);
}
}
Server server = new Server(8080);
server.setHandler(handler);
server.start();
כדי לגשת אליו, נפתח את הדפדפן על http://localhost:8080 במקרה שלנו.
עכשיו רק נשאר לקשור את החוטים ביחד.
פתחתי בלוג קטן לפרוייקט, וחיש מהר החשבון שלי בTorrentLeech הושעה. כשביררתי מה הסיפור נאמר לי שהם חוששים שאני אגנוב למשתמשים סיסמאות.
הצעתי להם לבדוק את הקוד, ושעד אז אני אוריד את הלינק, וכך עשיתי, והחשבון שלי שוחזר.
בינתיים הם עדיין לא חזרו אלי, והסבלנות קצת פקעה.
מי שרוצה להוריד את הקוד יכול להוריד אותו מפה עם לקוח Subversion.
מי שרוצה להוריד את הבינארי מוזמן להוריד אותו מפה.
יש הוראות שימוש בתוך קובץ הREADME.
tl2rss משוחרר תחת רשיון GPL-3.0.
10 תגובות »
נכתב על ידי סשה בנושא Java, אינטרנט, מחשבים, תכנות
לאחר חודשים של עבודה מפרכת שחררתי היום את ספרית המפות מבוססת ה-Google Web Toolkit שלי. הספריה מאפשרת פיתוח אפליקציות web עם מפות בשפת Java (החביבה עלי וכן על עמרי עד מאוד), כשם ש-Google Maps API מאפשר זאת למפתחי JavaScript.
לאחר נסיוני המר עם ה-GPL פרסמתי את ספרית המפות תחת ה-CC BY-NC-SA.
יום הולדת שמח, עמרי, ותהנה מהאוגרים!
12 תגובות »
נכתב על ידי עמרי בנושא אינטרנט
אחרי תקופת מעבר ארוכה בה מאמצי מנהלי הרשת הופנו לבניית השרתים החדשים, hcoop.net פותחים את השערים למשתמשים חדשים.
hcoop הוא ארגון שלא למטרות רווח שמספק שרותי הוסטינג במחיר עלות לכמה מאות גיקים (העלות מתחלקת בין החברים בhcoop).
אני מאכסן בhcoop את הבלוג הזה, את firestats.cc ועוד כמה אתרים שונים ומשונים, והכל במשהו כמו 5$ לחודש.
מה שחשוב לי במיוחד, זה שאני מקבל גישת shell ואפשרות להריץ למעשה כל דבר שאני רוצה על השרת.
מנהלי הרשת מאוד גמישים ואם יש לכם בקשה מיוחדת יש סיכוי טוב שהיא תקבל מענה מספק.
בנוסף hcoop מאפשרים מספר בלתי מוגבל של הוסטים וירטואליים, שזה דבר נוח מאוד.
hcoop מומלץ רק למשתמשים שלא חוששים משורת הפקודה ומקריאת תיעוד.
הצטרפו בהמוניכם, תגידו שעמרי שלח אתכם :).
תגובה אחת »
נכתב על ידי עמרי בנושא FireStats, אינטרנט
IPV6 היא הגרסא הבאה של פרוטוקול האינטרנט, שכבר מתבשלת כמה שנים טובות.
השינוי המרכזי ביותר, והמוטיבציה הגדולה של השינוי נובעת מהבעיה המחריפה והולכת של חוסר בכתובות IP פנויות. בIPV4 - הגרסא הנוכחית, כל כתובת תופסת 4 בתים שהם 32 ביט, מה שאומר שיש 2 בחזקת 32 כתובות אפשריות שזה קצת יותר מארבע מיליארד כתובות אפשריות.
התקן של IPV4 נקבע ב1981, ארבע מיליארד כתובות נראו אז כמו הגזמה פראית, ואף אחד לא דימיין שבתוך כמה עשרות שנים יהיה צורך ביותר כתובות.
השוק התמודד עם המגבלה במספר כתובות הIP במספר צורות:
כתובות IP דינאמיות
כשהאינטרנט הפך לפופולרי, אנשים התחילו להתחבר בחיוג מהבית, מכיוון שהחיוב היה לפי דקה, לא היה הגיון בהקצאת כתובת IP לכל משתמש, שממילא היה מחובר רק לפרקי זמן קצרים. לכן ספקי שרות האינטרנט בחרו בגישה הנכונה של הקצאה דינמית של כתובת IP פנויה ברגע החיבור.
במהלך השנים טכנולוגית החיבור השתנתה, והיום רוב המשתמשים מחוברים לפרקי זמן ארוכים הרבה יותר, וחלק גדול מהם מחוברים בצורה קבועה. ההגיון במתן כתובת IP דינמית יורד משמעותית במצב כזה, אבל ספקי האינטרנט מעדיפים לא לשנות את המצב כי זה מאפשר להם לגבות יותר כסף ממשתמשים שרוצים כתובת קבועה (הנבלות).
NAT
מכיוון שאין מספיק כתובות IP לתת לכל מחשב או לכל מכשיר נייד (כן, לסלולרי שלכם יש כתובת IP), קמו חכמים וחשבו:
מה אם נגדיר טווח כתובות מיוחד (או כמה טווחים) שישמש לרשתות פנימיות בלבד, ולא יהיה חוקי באינטרנט הגדול?
זה יאפשר לנו לבחור כתובות IP למחשבים ברשת הפנימית שלנו בלי תלות במספר הכתובות האמיתיות שלנו (שעולות לא מעט).
הבעיה עם זה היא שאם הכתובות לא חוקיות באינטרנט, איך מחשב כזה יכול לתקשר עם מחשבים מחוץ לרשת הפנימית שלו (בה הכתובות חוקיות)?
ברגע שנתב שם בחוץ יראה חבילת מידע עם הכתובת שלו ככתובת יעד, הוא לא ידע לאן לנתב אותה ויזרוק אותה לסל המיחזור של החבילות.
הפתרון הוא NAT, או Network address translation. הרעיון די פשוט: נשים מחשב (או נתב) אחד עם כתובת IP אמיתית, וננתב את כל חבילות המידע שנשלחות החוצה מהרשת שלנו דרכו. המחשב הזה ישנה את פרטי החבילה כך שכתובת הIP ממנה היא נשלחה תהיה שלו, יזכור את פורט המקור של החבילה, וישלח אותה.
ברגע שמגיעה חבילה שממוענת אל אותו מחשב NAT, הוא יבדוק את החבילה, יסיק לפי מה שהוא זוכר לאיזה מחשב ברשת הפנימית החבילה ממוענת, יתקן את הכתובת והפורט לפרמטרים הנכונים ויעביר את החבילה.
גישה זו מאפשרת לרשת עם עשרות או מאות מחשבים להתחבר לאינטרנט עם כתובת IP אמיתית אחת בלבד.

שני הפתרונות האלו (ועוד כמה פחות משמעותיים) הורידו את דחיפות הפיתרון האמיתי, שהוא מעבר לIPV6.
IPV6
השינוי המרכזי בIPV6 הוא הרחבת טווח הכתובות האפשריות. במקום 4 בתים לכתובת IPV4, יש לא פחות מ16 בתים בכתובת IPV6.
קצת מתמטיקה:
4 בתים הם 32 סיביות. 2 בחזקת 32 זה 4,294,967,296,
4 מיליארד כתובות בIPV4.
16 בתים הם 128 סיביות, 2 בחזקת 128 זה:
340,282,366,920,938,463,463,374,607,431,770,000,000
340 מיליארד מיליארד מיליארד מיליארד כתובות בIPV6.
אז תחום הכתובות של IPV6 יספיק להרבה הרבה זמן.
שיפורים נוספים בIPV6
IPV4 לא תוכנן להיות מאובטח בשום רמה, ובשלב מסויים הוגדר תקן IPSec, אבל גם אחרי שהוא הוגדר הוא היה אופציונלי ולא מחויב.
בIPV6 לעומת זאת, האבטחה מוגדרת כחובה, והיא בנויה בצורה יותר טובה.
למשל, בIPV4 - נתמכת הצפנה של תוכן ההודעות בלבד (payload), ובIPV6 נתמכת הצפנה של התוכן והכותרת (header).
שיפורים נוספים הם תמיכה מובנית בתעדוף תעבורה מסויימת (QOS), הגדרה אוטומטית (Auto-configuration), חבילות נתונים גדולות לשיפור ביצועים ברשתות שמעבירות הרבה מאוד מידע (JumboGrams, חבילות נתונים בIPV4 מוגבלות לגודל של 65535 בתים, בIPV6 לעומת זאת החבילות יכולות להגיע לגודל 4 ג’יגה לחבילה)
למרות כל השיפורים הפרישה של IPV6 עדיין דלה ונקודתית.
וצפויים לפחות עוד כמה שנים טובות לפנישהתקן יצבור תאוצה (ויש מי שטוען שהוא לעולם לא יצבור תאוצה).
ייצוג טקסטואלי של כתובות IPV6
אנשים רגילים לכך שכתובת IP הן מהצורה המקובל של a.b.c.d, כאשר כל מספר הוא בן 0 ל255.
בIPV6 התמונה משתנה, במקום 4 קבוצות בין 0 ל255, פתאום יש לנו 8 קבוצות של 0 עד 65535, שמיוצגות בבסיס 16, ומופרדות על ידי נקודותיים.
למשך:
2001:0db8:0000:0000:0000:0000:1428:57ab
יהיה לא נעים להקריא את זה בטלפון.
כדי לעזור קצת, הוגדר הקיצור הבא:
סדרת אפסים אחת בכתובת יכולה להתכווץ לצמד נקודותיים, ואפשר גם להתעלם מאפסים שפותחים קבוצה - מה שאומר שאת הכתובת הזו אפשר לכתוב גם כך:
2001:db8::1428:57ab
קצת יותר טוב.
FireStats וIPV6.
עד גרסא 1.4, פיירסטטס מאכסן כתובות IP בתוך מחרוזת תווים, ולכן תומך גם בIPV4 וגם בIPV6.
אחד הפיצ’רים המבוקשים ביותר הוא היכולת להתעלם מטווח של כתובות IP.
עד 1.4, ניתן להוסיף כתובות מסויימות לרשימת ההתעלמות, אבל זה לא מספיק כשרוצים להתעלם מטווח שלם, למשל כדי לסנן את הספאם של מייקרוסופט.
כדי לתמוך בסינון לפי טווח כתובות, הכי טוב לשמור את כתובת הIP כמספר ולא כמחרוזת - כי אז אפשר לבדוק אם המספר נמצא בטווח בקלות.
אבל באיזה כתובות IP לתמוך?
אומנם 99% מהמשתמשים עובדים עם IPV4 בלבד, אבל אם אני אסתמך על זה, זה בעצם אומר שאני מבטל את התמיכה בIPV6, צולעת ככל שתהיה.
לא ממש רציתי לעשות את זה, ולכן החלטתי לתמוך בIPV6 גם אחרי המעבר משמירת כתובות טקסטאלית לשמירה מספרית.
אבל איך שומרים כתובת IPV6 בMySQL כמספר? הטיפוס המספרי הגדול ביותר בMySQL הוא BIGINT, שרוחבו 8 בתים, וסיכמנו כבר שכתובת IPV6 היא ברוחב 16 בתים.
הפתרון הוא להשתמש בשתי עמודות של BIGINT, אחת לחצי הימני של כתבות הIP והשניה לחצי השמאלי.
קצת מכוער, אבל זה המצב.
בעיה נוספת שצריכה התייחסות מיוחדת היא בעיית ההצגה והקליטה של כתובות IP.
כשמגיעה כתובת IP טקסטואלית למערכת, צריך להבין מאיזה גרסא היא, ולתרגם אותה לייצוג מספרי.
כשרוצים להציג כתובת IP מספרית, צריך לעשות את הפעולה ההפוכה ולהציג אותה בצורה הידידותית ביותר (IPV4 אם הכתובת המקורית היא בIPV4, אחרת IPV6).
מכיוון שהתמיכה בIPV6 בPHP די צולעת - קיימות פונקציות, אבל רק מגרסאות חדשות של PHP וגם אז הן לא נתמכות בכל מערכות ההפעלה - כתבתי את פונקציות ההמרה והזיהוי בעצמי.
אפשר לראות בתמונה טווח IPV6 ליד כתובת IPV4 בודדת:

קריאה נוספת:
IPv6: The Promise, The Problems, The Protocol
ווקיפדיה
8 תגובות »
|